Skip to content
This repository has been archived by the owner on Jan 20, 2024. It is now read-only.

Refresh token flow adds always Authorization header #196

Open
lanbotdevman opened this issue Aug 17, 2022 · 0 comments
Open

Refresh token flow adds always Authorization header #196

lanbotdevman opened this issue Aug 17, 2022 · 0 comments

Comments

@lanbotdevman
Copy link

lanbotdevman commented Aug 17, 2022

Context:

  • AWS Cognito Oauth2 server
  • Public web client that has no client secret (only client ID is available)
  • Upon initialization, only refresh token is available (in addition to static conf, for example client ID)

Main problem

When using a public web client that does not have client secret, the ClientOAuth2 client sends Authorization header to OAuth2 token endpoint

The failure (in case of AWS) is caused by two following reasons:

  • Refresh logic assumes always that client ID and client secret are present
  • In case of AWS Cognito OAuth2, the header should not be sent at all - instead the client_id should be in the payload

First part cannot be fixed with options since Object.assign() is used default header cannot be used to override the Auhtorization header:

    headers: Object.assign({}, DEFAULT_HEADERS, {
      Authorization: auth(options.clientId, options.clientSecret)
    }),

Second part can be improved by adding body.client_id option in the refresh method:

      token.refresh({
        body: {
          client_id: '<YOUR_CLIENT_ID>',
        },
      })

Steps to reproduce (pre-reqs):

  • Set up AWS Cognito User pool
  • Add App Integration with no client secret
  • Create token using"Authorization Code Grant" flow

Steps to reproduce (client auth flow)

  • Initialize the web client
  • Create a ClientOAuth2 client instance with static conf
  • Authenticate the user against OAuth2 server using "Authorization Code Grant" flow ClientOAuth2.code.getUri())
  • Store the refresh token in the cookies during the callback
  • Re-initialize the client (no token in memory, only refresh token in cookies)
  • Create ClientOAuth2 client instance with static conf
  • Create ClientOAuth2.Token using refresh token from the cookies
  • Refresh the token
  • Example code snippet:
      const client: ClientOAuth2 = new ClientOAuth2({
        clientId,
        accessTokenUri,
        authorizationUri,
        redirectUri,
        scopes,
      });

      const token: ClientOAuth2.Token = client.createToken({
        refresh_token: refreshToken,
      });

      token.refresh({
        body: {
          client_id: '<YOUR_CLIENT_ID>',
        },
      })
        .then(token => {
          // TODO Business logic to handle the new fresh token, e.g. store access token in the cookies
        });

Expected result: fresh access token is returned from the token endpoint
Actual result: request fails with HTTP 400 {"error":"invalid_client"}

Suggestions

One obvious and simple fix is to add Authorization header only if both, client ID and secret, are present.
Adding the client_id automatically to the body automatically might not be correct - I did not find relevant specification on that flow, thus it could be specific to AWS Cognito.

Additional references

OpenID spec: https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
Client Authentication → none → The Client does not authenticate itself at the Token Endpoint, either because it uses only the Implicit Flow (and so does not use the Token Endpoint) or because it is a Public Client with no Client Secret or other authentication mechanism.

AWS Cognito Token endpoint documentation: https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html

Similar issue was reported also on a more general level: #133. For example, AWS supports also authorization via POST body parameters, but I created this new issue specifically because ClientOAuth2 adds an invalid header, thus breaking the flow.

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

No branches or pull requests

1 participant