1

I'm trying to implement a OAuth2 Authorization Server using DotNetOpenAuth. The client is JavaScript based thus incapable of holding any secrets. This is exactly the same problem like this question but with another framework.

The client requests (against the token endpoint) access_token and refresh_token with following parameters:

  • grant_type: password
  • username: foo
  • password: bar

This does work. Now I want use the refresh_token and make a request against the token endpoint with the following parameters:

  • grant_type: refresh_token
  • refresh_token: ABCDEF

This gives me the following response:

{"error":"invalid_client","error_description":"The client secret was incorrect."}

Which does make (at least some) sense because RFC6749 states that:

Because refresh tokens are typically long-lasting credentials used to request additional access tokens, the refresh token is bound to the client to which it was issued. If the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), the client MUST authenticate with the authorization server as described in Section 3.2.1.

If I change my request like so:

  • grant_type: refresh_token
  • refresh_token: ABCDEF
  • client_id: MYCLIENT
  • client_secret: CLIENT_SECRET

The problem is my client is not supposed to be confidential (because it is client side JavaScript after all).

This is how the client is defined:

New ClientDescription(ApiKey, New Uri(allowedCallback), ClientType.Public)

I searched through the DotNetOpenAuth source code and found no use of the ClientType. To me it looks like it is not used at all.

It is also not possible to the set an empty client secret, because the DotNetOpenAuth source code actively checkes against this (ClientAuthenticationModules.cs):

                if (!string.IsNullOrEmpty(clientSecret)) {
                    if (client.IsValidClientSecret(clientSecret)) {
                        return ClientAuthenticationResult.ClientAuthenticated;
                    } else { // invalid client secret
                        return ClientAuthenticationResult.ClientAuthenticationRejected;
                    }
                } else { // no client secret provided
                    return ClientAuthenticationResult.ClientIdNotAuthenticated;
                }

If I take a look at MessageValidationBindingElement.cs:

        if (authenticatedClientRequest != null) {
            string clientIdentifier;
            var result = this.clientAuthenticationModule.TryAuthenticateClient(this.AuthServerChannel.AuthorizationServer, authenticatedClientRequest, out clientIdentifier);
            switch (result) {
                case ClientAuthenticationResult.ClientAuthenticated:
                    break;
                case ClientAuthenticationResult.NoAuthenticationRecognized:
                case ClientAuthenticationResult.ClientIdNotAuthenticated:
                    // The only grant type that allows no client credentials is the resource owner credentials grant.
                    AuthServerUtilities.TokenEndpointVerify(resourceOwnerPasswordCarrier != null, accessTokenRequest, Protocol.AccessTokenRequestErrorCodes.InvalidClient, this.clientAuthenticationModule, AuthServerStrings.ClientSecretMismatch);
                    break;
                default:
                    AuthServerUtilities.TokenEndpointVerify(false, accessTokenRequest, Protocol.AccessTokenRequestErrorCodes.InvalidClient, this.clientAuthenticationModule, AuthServerStrings.ClientSecretMismatch);
                    break;
            }

Espacially the comment The only grant type that allows no client credentials is the resource owner credentials grant. makes me wonder. Does that mean that in my scenario the JS client should send username/password along? Nope this will raise the following exception:

AccessTokenResourceOwnerPasswordCredentialsRequest parameter 'grant_type' to have value 'password' but had 'refresh_token' instead.

Which is okay to me, because I don't want the client to keep the password.

So here my questions:

  • Did I unterstand something fundamentally wrong about the password-grant, refresh_token scheme?
  • As I see it in a JS client the client_id is public knowledge, so it does not serve any security purpose. Am I correct?
  • Does it makes sense to change DotNetOpenAuth to make use of the ClientType.Public?
  • Would it make any difference if I just use client_id and client_secret as not secret? E.g. just supply dummy values? What are the security implications?
Community
  • 1
  • 1
dummy
  • 4,256
  • 3
  • 25
  • 36

0 Answers0