1

I'm redirecting my user to Cognito hosted UI, then returning to my PHP application. If the code is found then I use Guzzle to exchange this with the access tokens, however I keep on receiving the following error:

{"error":"unauthorized_client"}

This is my code, I have double checked what i'm passing in with the documentation and it all looks fine to me!

if ($code = request()->input('code')) {
    $client = new Client();
    $confirmCodeDomain = "https://$domain/oauth2/token";
    try {
        $result = $client->post($confirmCodeDomain, [
            'form_params' => [
                'grant_type' => 'authorization_code',
                'client_id' => $client_id,
                'code' => $code,
                'redirect_uri' => 'https://localhost/auth/',
            ],
            'headers' => [
                'Content-Type' => 'application/x-www-form-urlencoded',
                'Authorization' => 'Basic '.base64_encode("$client_id:$client_secret")
            ]
        ]);
    } catch (\Exception $e) {
        dd($e);
    }
    
    dd($result);
}

This is my serverless file which creates the AWS resources required, the error states:

unauthorized_client Client is not allowed for code grant flow or for refreshing tokens.

However as you can see from my client definition the AllowedOAuthFlows is set to code:

resources:
  Resources:
    CognitoEmployeePool:
      Type: AWS::Cognito::UserPool
      Properties:
        UserPoolName: employees
        MfaConfiguration: OFF
        AdminCreateUserConfig:
          AllowAdminCreateUserOnly: true
        Policies:
          PasswordPolicy:
            MinimumLength: 7
            RequireLowercase: true
            RequireUppercase: true
            RequireNumbers: false
            RequireSymbols: false
        EmailConfiguration:
          EmailSendingAccount: "COGNITO_DEFAULT"
        UsernameAttributes:
          - email
        AutoVerifiedAttributes:
          - email
    CognitoEmployeePoolClient:
      Type: AWS::Cognito::UserPoolClient
      Properties:
        ClientName: employees-webplanner
        CallbackURLs:
          - "https://localhost"
          - "https://localhost/auth"
        AllowedOAuthFlowsUserPoolClient: true
        SupportedIdentityProviders:
          - "COGNITO"
        AllowedOAuthFlows:
          - "code"
        AllowedOAuthScopes:
          - "openid"
          - "email"
        UserPoolId:
          Ref: CognitoEmployeePool
        ExplicitAuthFlows:
          - ALLOW_ADMIN_USER_PASSWORD_AUTH
          - ALLOW_REFRESH_TOKEN_AUTH
          - ALLOW_USER_PASSWORD_AUTH
        GenerateSecret: true
    CognitoEmployeePoolDomain:
      Type: AWS::Cognito::UserPoolDomain
      Properties:
        UserPoolId: !Ref CognitoEmployeePool
        Domain: "marvs-sso"

Martyn Ball
  • 4,679
  • 8
  • 56
  • 126
  • I think in headers you must use a ':' colon in between key value pair and it's missing in your case – BlackXero May 25 '22 at 13:55
  • @BlackXero This gets added by Guzzle – Martyn Ball May 25 '22 at 15:18
  • Did you ever figure this out? – RobH Aug 18 '22 at 11:26
  • @RobH I'm afraid not. – Martyn Ball Aug 18 '22 at 12:52
  • @MartynBall Any success? I get the same error and none of the other SO QAs (like [this](https://stackoverflow.com/questions/50264679/aws-cognito-unauthorized-client-error-when-hitting-oauth2-token) one) have helped. On the first invocation of the endpoint I get the same `unauthorized_client` error that you get. If I invoke it again with the same payload, I get `invalid_grant`, which makes sense, since according to the [docs](https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html#post-token-negative) this happens when "Authorization code has been consumed already". – Ricardo van den Broek Jul 05 '23 at 19:27

1 Answers1

0

TL;DR

Make sure that redirect_uri matches what you sent to /login. Apparently they have to be the same.

Explanation

I struggled with seemingly the same thing:

  • Successfully can get a code from Cognito's /login endpoint
  • 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 applies to /login as well.