How to use the code returned from Cognito to get AWS credentials?

you can find the "Authorization code grant" in the doc :http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-idp-settings.html


To fetch AWS credentials (id_token, access_token and refresh_token) from the code request parameter returned by the authorisation code oath2 flow, you should use your Cognito User Pool web domain /oauth2/token endpoint, following https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html instructions.

Pay attention to the HTTP Basic Authorisation user and password instructions, it should be your Cognito App client_id and client_secret, otherwise, you get a invalid_client error.

The code flow is supposed to be used server side, as you avoid tokens floating around on URLs. If you're planning to do that client side, you should use the response_type=token, as it gives this result directly on the login redirect.


First off, screw authentication a thousand times. No one deserves to spend half a day looking at this shit.

Authentication for API Gateway Authorized with Cognito

Ingredients

  1. client_id and client_secret: In Cognito > General Settings > App clients you can find the App client id, then click on Show Details to find the App client secret

  2. For the header Authorization: Basic YWJjZGVmZzpvMWZjb28zc... you need to encode those two with: Base64Encode(client_id:client_secret), for example in Python:

    import base64  
    base64.b64encode('qcbstohg3o:alksjdlkjdasdksd')`  
    

    side note: Postman also has an option to generate this in Authorization > Basic Auth

  3. redirect_uri: passed in the body, it is the callback url that you configured in App integration > App client settings.
    This MUST match with what you configured or you will get a totally unhelpful message { "error": "invalid_grant" }

Example of a request to get a token from the code:

curl --location --request POST 'https://mycognitodomain.auth.us-east-1.amazoncognito.com/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic <base64 encoded client_id:client_secret>' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=<client_id>' \
--data-urlencode 'code=<use the code you received post login>' \
--data-urlencode 'redirect_uri=https://myapp.com'

This will return your tokens:

{
  "access_token":"eyJz9sdfsdfsdfsd", 
  "refresh_token":"dn43ud8uj32nk2je",
  "id_token":"dmcxd329ujdmkemkd349r",
  "token_type":"Bearer", 
  "expires_in":3600
}

Then take the id_token and plug into your API call:

curl --location --request GET 'https://myapigateway.execute-api.us-east-1.amazonaws.com/' \
--header 'Authorization: <id_token>'

Ok, this is tagged as JavaScript but since we also suffer in Python

Friendly reminder: this is an example, please don't hardcode your secrets.

import requests

# In: General Settings > App clients > Show details
client_id = "ksjahdskaLAJS ..."
client_secret = "dssaKJHSAKJHDSsjdhksjHSKJDskdjhsa..."

# URL in your application that receives the code post-authentication
# (Cognito lets you use localhost for testing purposes)
callback_uri = "http://localhost:8001/accounts/amazon-cognito/login/callback/"

# Find this in: App Integration > Domain
cognito_app_url = "https://my-application-name.auth.us-west-2.amazoncognito.com"

# this is the response code you received - you can get a code to test by going to
# going to App Integration > App client settings > Lunch Hosted UI
# and doing the login steps, even if it redirects you to an invalid URL after login
# you can see the code in the querystring, for example:
# http://localhost:8001/accounts/amazon-cognito/login/callback/?code=b2ca649e-b34a-44a7-be1a-121882e27fe6
code="b2ca649e-b34a-44a7-be1a-121882e27fe6"

token_url = f"{cognito_app_url}/oauth2/token"
auth = requests.auth.HTTPBasicAuth(client_id, client_secret)

params = {
    "grant_type": "authorization_code",
    "client_id": client_id,
    "code": code,
    "redirect_uri": callback_uri
}

response = requests.post(token_url, auth=auth, data=params)

print(response.json()) # don't judge me, this is an example

Not sure if this is going to be useful 10 months from since it was asked but might be helpful to others.

I have used response_type=token (Oauth flow=implicit grant & scope=openid) & provider as Cognito. After you login using the default login page, you will get an id_token & access_token. You can get a temporary identity for your user using this id_token. You also need to have an Federated identity pool setup for this, with roles assigned for authenticated & unauthenticated users, and linked to the user pool you are authenticating with. Once you have that (assuming you are using javascript), you can follow example at Cognito user identity pools javascript examples. My sample code derived from the same -

function getAccessToken(idToken, identityPoolId, userPool) {
        let provider = "cognito-idp.us-east-2.amazonaws.com/" + userPool;
        let login = {};

        login[provider] = idToken;

        // Add the User's Id Token to the Cognito credentials login map.
        let credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: identityPoolId,
            Logins: login
        });

        //call refresh method in order to authenticate user and get new temp credentials
        credentials.get((error) => {
            if (error) {
                console.error(error);

                let response = {
                    statusCode: 500,
                    body: JSON.stringify(error)
                };

                return response;

            } else {
                console.log('Successfully logged!');
                console.log('AKI:'+ credentials.accessKeyId);
                console.log('AKS:'+ credentials.secretAccessKey);
                console.log('token:' + credentials.sessionToken);

                let response = {
                    statusCode: 200,
                    body: JSON.stringify({
                        'AKI': credentials.accessKeyId,
                        'AKS': credentials.secretAccessKey,
                        'token': credentials.sessionToken
                    })
                };

                return response;
            }
        });
    }

Hope this helps.