'AWS Cognito; unauthorized_client error when hitting /oauth2/token

Steps taken so far:

  • Set up new user pool in cognito
  • Generate an app client with no secret; let's call its id user_pool_client_id
  • Under the user pool client settings for user_pool_client_id check the "Cognito User Pool" box, add https://localhost as a callback and sign out url, check "Authorization Code Grant", "Implicit Grant" and everything under "Allowed OAuth Scopes"
  • Create a domain name; let's call it user_pool_domain

Create a new user with a username/password

Now, I can successfully go to:

https://{{user_pool_domain}}.auth.us-east-2.amazoncognito.com/oauth2/authorize?response_type=code&client_id={{user_pool_client_id}}&redirect_uri=https%3A%2F%2Flocalhost

This presents me with a login page and I am able to login as my user which returns me to https://localhost/?code={{code_uuid}}

I then try the following: curl -X POST https://{{user_pool_domain}}.auth.us-east-2.amazoncognito.com/oauth2/token -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=authorization_code&redirect_uri=https%3A%2F%2Flocalhost&code={{code_uuid}}&client_id={{user_pool_client_id}}'

However, this just returns back the following: {"error":"unauthorized_client"}

The token endpoint docs say that unauthorized_client is because "Client is not allowed for code grant flow or for refreshing tokens." which is confusing because I checked the boxes allowing the client to use the code grant flow.



Solution 1:[1]

So, it turns out that the user pool has to have a trailing slash (https://localhost/) and then that trailing slash has to be used in all of the callback URLs. Then it decides to work!

Solution 2:[2]

Everything looks OK to me. I think it may be complaining about the Authorization header missing but not sure. You could try a few things:

1) According to this page (https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html), you shouldn't need to send the Authorization header in the token request, but maybe it is still needed. You could try either passing just the client ID in it (Authorization [client ID]) or configure a secret and try passing Authorization [client ID:client secret] like it says). It usually makes sense to use a client secret for authorization code flow anyway since in this flow, there is a server side component that can securely handle the token exchange.

2) Try using Implicit Flow instead to see if that works. Implicit Flow makes sense for single page apps with no server side component. For that, no client secret is needed.

Solution 3:[3]

If you are using amplify and have it configured outside of the CLI and the other answers aren't working for you, one last fix you can try is to ensure you have responseType: 'token' if you are using implicit flow. Fixed things for me.

Auth: {
  oauth: {
    domain : 'your-app.auth.your-region.amazoncognito.com',
    redirectSignIn: environment.cognito.oauthCallbackLogin,
    redirectSignOut: environment.cognito.oauthCallbackLogout,
    responseType: 'token',
    scope : ['email', 'openid', 'profile'],
  }
}

Solution 4:[4]

Make sure to also include the scope in the request. Like the following

https://domain.auth.eu-central-1.amazoncognito.com/signup?client_id={}&response_type=token&scope=aws.cognito.signin.user.admin+email+openid+phone+profile&redirect_uri=https://www.google.com/

Solution 5:[5]

I had this error for another reason: I had response_type=token in the request URL, but the implicit OAuth flow was not enabled in the user pool client, so I needed to change it to response_type=code.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 TranquilMarmot
Solution 2 Andrew
Solution 3 williamsandonz
Solution 4 Lejdi Prifti
Solution 5 ak1ra