Cognito returns invalid_request and unauthorized_client

0

Hi, when we try to get the tokens from token endpoint using authorization code, we get invalid request and unauthorized responses. We use PKCE flow, hence we have setup two clients, one with secret and other without secret. Both clients have Authoriztion Code flow enabled. All the required paramenters are provided, properly posted in querystring format in the request body, method is set to Post, Content-Type is set, Authorization header is present for client with secret, the parameters provided are all correct and exactly the same as defined in the console. No issues with double URL-encoding or things of that sort. We need to know where Cognito emits the logs with reasons as to why it rejects the requests. Console log in lambda with Cloud watch is there, but it the response provided by cognito. So where can we find detailed logs? And the reason for trying with a client secret is to see if we can hide the refresh token in the server. But we are ready to leave that route, if the client without secret can respond with tokens.

2 Answers
1

It was a mistake of URL-encoding redirect_uri in the Post request that caused unauthorized_client error. invalid_client was due to mismatch in the way code verifier was used. Here are some confirmations, we can use PKCE against a client with Secret in Cognito, as of now. During sign in format for code_challenge is Base64(SHA256(code-verifier)). During code exchange pass the code-verifier as it is without Base64 encoding.

answered 2 years ago
0
Accepted Answer

Hello there,

From the description of the issue, I gather that you are leveraging the PKCE extension to secure the authorization code exchange while retrieving the tokens from your Cognito domain's oauth2/token endpoint. But while doing so, you are encountering the 400 series HTTP error codes, "Invalid_Grant" and "Invalid Request"[1].

At the time of posting this answer, I see that you were able to resolve the issue. For future references and other developers that are encountering this issue, I'm pasting below the generic issues that are usually encountered with the setup that is described above.

Setting PKCE extension/flow aside, when you hit your Cognito user pool domain's /oauth2/token endpoint and encounter the error message "invalid_request", it indicates that one or more of the request parameters in the header/body is incorrect or missing. Now, if the request is retried (while the "code" request parameter is kept the same), you would encounter an "invalid_grant" error message, and this is expected. The authorization code once consumed, cannot be used again. Also, the authorization code has to be consumed by the token endpoint within 5 minutes of its generation[2].

Upon bringing PKCE extension into the above mix, the same error sequence of "invalid_request" and "invalid_grant" is expected if the code verifier and code challenge don't match. As per RFC standards[3], the code challenge is derived in the following manner from the code verifier string.

plain code_challenge = code_verifier

S256 code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

Having stated the above, provided that the request parameters 'client_id', 'redirect_uri' and the 'Authorization' header (if your app client has a client secret) are accurate, the two most probable causes for this issue are:

  • Incorrect/Expired Authorization code
  • Mismatch between the code_challenge string sent in the '/authorize' request and the code_verifier string sent in the '/token' request. Kindly ensure that the code_challenger is encoded as per the above process[3].

For testing purposes, you may use the 2 functions from the below python snippet to:

  • Generate a code_verifier and it's code_challenger counter part. (For experimental purposes)
  • Check if the code_verifier and challenger generated by your application are valid.
---
import base64
import string
import random
import hashlib

def generate_code():
    rand = random.SystemRandom()
    code_verifier = ''.join(rand.choices(string.ascii_letters + string.digits, k=128))
    code_sha_256 = hashlib.sha256(code_verifier.encode('utf-8')).digest()
    b64 = base64.urlsafe_b64encode(code_sha_256)

    code_challenge = b64.decode('utf-8').replace('=', '')
    return ("\nCode verifier: '{0}'\n\nCode challenge: '{1}'\n".format(code_verifier, code_challenge)) 


def checkCodeChallengeAndVerifier(code_verifier, code_challenge):
    # Returns True if the Code verifier matches with the code challenge, else False
    return code_challenge ==  base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode('utf-8')).digest()).decode('utf-8').replace('=', '')
---

Checking if the code_verifier and code_challenger are the corresponding counterparts will help eliminate double URL encoding and other issues contributed with PKCE in the token retrieval process. Please do feel free to raise a technical support case with us if you continue to experience issues post passing the above 2 checks.

Moving ahead to viewing logs; although not verbose, you may view your Amazon Cognito Domain endpoint interactions via Amazon CloudTrail[4].

I hope the above shared information is helpful. If you require assistance with further troubleshooting, please open a support case and we'll be glad to assist :)

=================

References:

[1]. Examples of negative responses https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html#post-token-negative

[2]. Authorize endpoint - Examples requests with positive responses (Take a look at the 'Note' section) https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html#get-authorize-positive

[3]. Proof Key for Code Exchange by OAuth Public Clients - Derivation (Refer section 4.2) https://www.rfc-editor.org/rfc/rfc7636#page-8

[4]. Amazon Cognito information in CloudTrail https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-info-in-cloudtrail.html

AWS
SUPPORT ENGINEER
answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions