35

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.

TranquilMarmot
  • 2,034
  • 2
  • 19
  • 25
  • 8
    As Andrew noted, you can get this error when there is a problem with the `redirect_uri`. Using localhost has never been a problem for me, but I do get this (rather misleading) error message whenever I omit the trailing slash on the `redirect_uri` when calling the `token` endpoint. Can you try adding `%2F` to the end of the `redirect_uri`? – Mike Patrick May 10 '18 at 14:53
  • 1
    @MikePatrick WOW thank you so much! It was the missing trailing slash. That's a frustratingly bad error message that I lost a day on but it actually works now!!! – TranquilMarmot May 10 '18 at 15:46
  • 1
    I found that this also holds if I have a list of redirect uris defined in the app client at the AWS side - when I replaced the list with a single item, and had the client refer to the single item, it worked. Otherwise, I got the redirect_uri error mentioned. – Per Christian Henden May 30 '20 at 08:26

11 Answers11

60

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!

TranquilMarmot
  • 2,034
  • 2
  • 19
  • 25
  • 14
    You saved my day. The `redirect_uri` should be exactly the same as we define in Cognito console – rioastamal Oct 26 '19 at 03:06
  • 2
    concur to what @rioastamal says. Trailing slash isnt needed but the redirect_uri should be exactly the same as defined in the User Pool for "Callback URL(s)" ex: https://**DOMAINPREFIX**.auth.**REGION**.amazoncognito.com/oauth2/token?grant_type=authorization_code&client_id=**CLIENTID**&code=**AUTHORIZATION_CODE_OBTAINED_FROM_oauth2/authorize_ENDPOINT**&redirect_uri=**CALLBACK_URL_CONFIGURED_IN_USERPOOL** – kiran01bm Dec 04 '19 at 08:49
  • 1
    @kiran01bm lol this was the issue with my configuration. Thanks for pointing it out. I can finally go to sleep... – hwkd Sep 17 '20 at 16:35
  • 2
    This is so random and not documented in amazon cognito, thank you a lot! This is true for custom domains and urls too: `https://example.test/login/` – Timo Huovinen Feb 21 '22 at 17:29
  • 2
    I love you. After hours of scratching my head, who would have thought the answer was a measly "/". – wawaloo_17 Aug 24 '22 at 05:19
  • I agree that the URLs must match exactly. However I have not found that they must end in a '/'. I am using `http://localhost:9090/login` just fine. – Fonnae Mar 29 '23 at 21:34
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.

ak1ra
  • 383
  • 4
  • 8
4

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.

Andrew
  • 1,581
  • 3
  • 18
  • 31
  • I've tried it with the clientID:clientSecret base64 encoded as the Authorization header with no luck. How would I go about using the Implicit Flow? What's the difference? – TranquilMarmot May 10 '18 at 03:21
  • I noticed that AWS API Gateway will throw an "unauthorized" error if the redirect URI is not accessible. Now that I think about it, trying to use localhost may be a problem. Think about it ... AWS would need to redirect to that page but it can't because localhost is on your local machine. I would try a non-localhost URL to see if that is causing the problem. – Andrew May 10 '18 at 03:31
  • Here is info about the differences between authorization code flow and implicit flow: https://stackoverflow.com/questions/16321455/what-is-the-difference-between-the-2-workflows-when-to-use-authorization-code-f?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – Andrew May 10 '18 at 03:32
  • If you want to use Implicit Flow, then it is similar to what you just did except the last step is not needed. Instead, you would receive the token from the first request. It is provided in what is known as a URL fragment. The URL fragment can only be read by browsers. This fragment contains the token(s). – Andrew May 10 '18 at 04:03
4

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'],
  }
}
williamsandonz
  • 15,864
  • 23
  • 100
  • 186
1

I agree with @rioastamal and @kiran01bm as well. I did not need a trailing slash and it has to be verbatim as configured for the callbacks.

In my case I had my Redirect URI encoded at definition like this const redirectUri = encodeURIComponent(REDIRECT_URI). Later, when it was used in the POST call to the /token endpoint as part of the params, it resulted as a double-encoded string.

A facepalm moment, but could happen to anyone. Getting rid of one of the encoding fixed it for me.

savimonty
  • 11
  • 2
1

I configured the UserPoolClient via cloudformation and had the AllowOAuthFlows set to implicit, where to work with amplify/cognito I needed that value to be code.


  GoogleUserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    DependsOn: GoogleUserPoolIdentityProvider

    Properties:
      UserPoolId:!Ref MyUserPool
      AllowedOAuthFlowsUserPoolClient: true
      GenerateSecret: false
      CallbackURLs:  
        - http://localhost:8080
      LogoutURLs:
        - http://localhost:8080
      AllowedOAuthFlows:
        - code
      AllowedOAuthScopes:
        - email
        - openid
      SupportedIdentityProviders:
        - Google
monkut
  • 42,176
  • 24
  • 124
  • 155
1

TL;DR

In addition to all the other answers: Make sure that redirect_uri matches what you sent to /login. Apparently they have to be the same.

Explanation

After applying the existing answers, I was still having trouble:

  • I could successfully get a code from Cognito's /login endpoint
  • But when trying to convert the code to a token using /oauth2/token it fails with unauthorized_client

The part I was doing wrong is outlined in this documentation on the redirect_uri parameter:

redirect_uri Must be the same redirect_uri that was used to get authorization_code in /oauth2/authorize.

Although I got the authorization code from /login and not /oauth2/authorize, this apparently applies to /login as well.

0

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/
Lejdi Prifti
  • 183
  • 6
0

I my case, the issue came from the ACS URL that was incorrect, but so close that I did not see it. It was redirecting my to a page with this error "An error was encountered with the requested page."

fallais
  • 577
  • 1
  • 8
  • 32
0

Authorization code grant means you get a code at the end of that redirect and you have to exchange that code for the respective tokens, and the response Type will be code. And the Implicit grant type is the equivalent of response type token, where in you will get the tokens on the first step itself. So check if you have the correct response type as per your auth flow set in the cognito console.

0

In my case, I updated the localhost:port in Allowed callback URLs of cognito app client setting but failed to add localhost:port to Allowed sign-out URLs

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 24 '23 at 01:01