jhipster oauth2 client secret

2019-03-16 17:31发布

问题:

I've been experimenting with jhipster. I've configured my app to work with oauth2. For that purpose I have a client secret in my application.yml

According to several articles I have found on this topic, the client secret should be kept secret at all times. For example, check https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified

The client secret must be kept confidential. If a deployed app cannot keep the secret confidential, such as Javascript or native apps, then the secret is not used.

I've noticed though that the generated auth.oauth2.service.js contains the secret in plain text:

        return {
            login: function(credentials) {
                var data = "username=" + credentials.username + "&password="
                    + credentials.password + "&grant_type=password&scope=read%20write&" +
                    "client_secret=mySecretOAuthSecret&client_id=myapp";
                return $http.post('oauth/token', data, {
                    headers: {
                        "Content-Type": "application/x-www-form-urlencoded",
                        "Accept": "application/json",
                        "Authorization": "Basic " + Base64.encode("myapp" + ':' + "mySecretOAuthSecret")
                    }
                }).success(function (response) {
                    var expiredAt = new Date();
                    expiredAt.setSeconds(expiredAt.getSeconds() + response.expires_in);
                    response.expires_at = expiredAt.getTime();
                    localStorageService.set('token', response);
                    return response;
                });
            },

I understand that it will be a little bit harder to find in the minified javascript, but anyone looking for 'client_secret' will be rewarded quickly.

Am I missing something? Or is the jHipster oauth implementation unsafe?

Thanks, Andy

回答1:

Since a JS client like jhipster's can't keep the client-secret "secret", it doesn't make sense to use the client-secret at all. The OAuth2 Resource Owner Password Credentials Grant flow that jhipster uses is for very trusted clients--which the client side of jhipster is. It allows for you to skip the normal "authorize" endpoint and go directly to the "token" endpoint to get your tokens with your user credentials. If your Spring Authorization Server (AS) defines a client-secret, you'll need to pass that secret along from the client JS. However, if you remove the secret definition from your in-memory client setup in your AS (e.g. comment out that line in OAuth2ServerConfiguration.java), you can leave it out altogether in your JS (see below)

return {
   login: function(credentials) {
      var data = "username=" + credentials.username + "&password=" + credentials.password + "&grant_type=password&scope=read%20write&";
      return $http.post('oauth/token', data, {
         headers: {
            "Content-Type": "application/x-www-form-urlencoded",
            "Accept": "application/json",
            "Authorization": "Basic " + Base64.encode("myapp" + ':' + "")
         }
      }).success(function (response) {
         var expiredAt = new Date();
         expiredAt.setSeconds(expiredAt.getSeconds() + response.expires_in);
         response.expires_at = expiredAt.getTime();
         localStorageService.set('token', response);
         return response;
      });
   },

After removing your client-secret, I don't think your app is really any safer but it feels a bit cleaner and honest--in that you're acknowledging that using a JS-only client, you can only be so safe. For JS and native clients, the implicit flow is typically used and it doesn't bother with a client-secret. It's simplified from the more robust authorization code grant flow for the fact that with a JS or native client can't keep a secret.

Anyway, jhipster probably shouldn't have the client-secret in the JS source but I don't believe it's doing any harm (since the only alternative is to have a blank client-secret which isn't any more secure). You're not unsafe (as the spec allows for this kind of thing) but you'd be safer using the authorization code flow (which would require a little work in the jhipster implementation) or to have a light server proxy add the client-secret to the request to the "token" endpoint rather than from the JS directly. Server to server communication (e.g. via a proxy) keeps secrets away from the view of the browser.

see this post for a nice discussion of the pitfalls of a JS-only client with oauth2: http://alexbilbie.com/2014/11/oauth-and-javascript/

here's an example of using oauth2 with angularjs and spring over a proxy: https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v