Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

token handler throwing InvalidClientError even through requireClientAuthentication is false for password grant #676

Open
rhenretta opened this issue Feb 19, 2021 · 2 comments

Comments

@rhenretta
Copy link

rhenretta commented Feb 19, 2021

I'm trying to create an access_token for a password flow, however the current implementation makes this impossible.

routes.oauth = new OAuth2Server({
  model: user.schema.methods,
  grants: ['password'],
  debug: true
});

routes.post('/token', express.urlencoded(), async (req, res, next) => {
  const request = new OAuth2Server.Request(req);
  const response = new OAuth2Server.Response(res);
  const options = {
    requireClientAuthentication: { 
      password: false 
    }
  }
  const result = await routes.oauth.token(request, response, options);
  next();
});

my post body is x-form-urlencoded and contains key value pairs for grant_type = password, username, and password. No client_id is sent.

The error is raised from this function:

TokenHandler.prototype.getClientCredentials = function(request) {
  if (!this.isClientAuthenticationRequired(grantType)) {
    if(request.body.client_id) {
      return { clientId: request.body.client_id };
    }
  }

  throw new InvalidClientError('Invalid client: cannot retrieve client credentials');
};

since no client_id is included in the body, the error is thrown. If I do include an empty client_id in the body, then a different error is returned because no client_id exists.

@rhenretta
Copy link
Author

More info, from peaking around in the code. I tried adding a client_id to the request, thinking if I at least have a dummy client id and return the same client id in getClient in the model, I could make it work. Unfortunately, that doesn't work either.

PasswordGrantType doesn't set the client at all in the constructor. There isn't even a check in there if requireClientAuthentication is true or false.

In token-handler.js, we have this:

  return Promise.bind(this)
    .then(function() {
      return this.getClient(request, response);
    })
    .then(function(client) {
      return this.handleGrantType(request, client);
    })
    .tap(function(data) {
      var model = new TokenModel(data, {allowExtendedTokenAttributes: this.allowExtendedTokenAttributes});
      var tokenType = this.getTokenType(model);

      this.updateSuccessResponse(response, tokenType);
    }).catch(function(e) {
      if (!(e instanceof OAuthError)) {
        e = new ServerError(e);
      }

      this.updateErrorResponse(response, e);

      throw e;
    });

Here we getClient() (in this case my dummy client), which gets passed into handleGrantType. This creates a PasswordGrantType which does not set the client. That then gets sent into TokenModel, which checks the PasswordGrantType for a client. Since it is not set, it then throws an exception.

I haven't spent much time in the code, and thus don't know what the appropriate fix here is.

@aramgyulnazaryan
Copy link

I also have the same issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants