Life is too short not to test your API served from AWS with Postman

How to get your AWS provisioned API that requires Cognito authentication and authorization to play nice with Postman

Boris Lipchin
7 min readNov 3, 2019

The situation:
I have an API provisioned by a serverless framework, that is authenticated and authorized by some complex weave of API Gateway, and Cognito.
The problem:
I want a tool that allows me to easily exercise this API, and also serves as explicit documentation for the interface
Stack:
AWS serverless, lambdas, API gateway, Cognito user pools, Cognito identity pool, IAM user roles, Postman
Solution:
I got it to work because I am too stubborn not to.

The background

I am a software engineer with simple needs and desires. I like fresh coffee with milk, mochi ice cream that is just a little melted, and tools that simultaneously serve as a testbed for your API while also providing necessarily accurate documentation for it thereby allowing you to ship code faster, with less stupid problems caused by poor communication on distributed team because you never got the chance to write that Trello card with the level of detail you should have.

The latter is a surprisingly hard thing to solve. Especially considering the ridiculous amount of people that have the problem, the tremendous amount of people that have written code to sell it to people like me, and the even larger group of people that have struggled to figure out how to do this and posted about it angerly on the internet.

So since I did not found a single blog anywhere that talked about how to do this in simple terms, here it is, in painful detail that took me a long time to figure out.

My setup

Cognito manages authentication (and in my case authorization) for your app defined by IAM roles. That means every time you create a user for your app a user is added to your Cognito user pool. When that user authenticates against your user pool, it gets an “Identity” from a (in my case) Cognito identity pool. That identity is authorized to access your various AWS resources (API gateway, DynamoDB, S3, etc) by a pre-defined IAM role.

Before you read

If an IAM user is all you need to authenticate your Postman calls, you don’t need to read 95% of this post. This is meant for folks that need a Cognito user pool user authenticated to invoke API calls (ostensibly from the front-end/mobile/etc). Also, I love errata, so please post it here, no matter how pedantic. I get it. I’ve been there.

What you’ll need

Have the AWS CLI tool setup and configured already.

Ability to patiently distinguish between “user pool” and “identity pool” in subsequent writing. They’re very different.

The fix part 1 — authenticate with Cognito user pool to get an ID token

Here you will simply “log in” with your desired user that will be the one “using” your API. For example, users that log-in to our front-end app have varying permissions to access various endpoints depending on who they are. People that haven’t logged in, get access to almost nothing.

First, you need some critical information. Remember this part is ALL about Cognito user pools and your user authenticating with a Cognito user pool.

Get your app client ID from the Cognito user pool config:
Go to the configuration menu for your relevant Cognito user pool. If you’re not sure which one you need — hint it’s the one that stores information for the users that you want to authenticate to test your API. In the App Clients configuration menu, you should see a reference to the ID for the “app client.” Save this, you will need it.

You will also need the username and password you would use to authenticate with Cognito the “regular” way, ostensibly online.

Assemble all that information in a file, I called user_auth.json since I expected to be using this a lot. You can also do everything else just command line if your heart desires it. Note “USER_PASSWORD_AUTH” is a thing you shouldn’t change.

{
"ClientId": "CLIENT_ID_FROM_PREVIOUS_STEP",
"AuthFlow": "USER_PASSWORD_AUTH",
"AuthParameters": {
"USERNAME": "some_username@awesomeco.com",
"PASSWORD": "your_super_secure_password"
}
}

Execute the following command.

$ aws cognito-idp initiate-auth --cli-input-json file://user_auth.json

It will spit out a bunch of information, you just need the ID token. My AWS CLI output is configured to “json” so it’s easy to tell which is which, I imagine in other formats it may or may not be less easy. Either way, make sure you’re getting the ID token. AWS is not forgiving to mistakes like this.

Once you have it, congratulations, you’ve now “logged-in.” This should mean that your user has been granted an “identity.” This identity is the source of a “session” concept that exists in AWS authentication and authorization. It is this session that Postman will piggyback on to send API requests using this user’s (I should say identity’s) authorization.

The fix part 2 — get the Cognito identity pool ID

The goal here is to get the identity pool ID for your newly minted authenticated user. If you have a better way of doing it, or guessing, crystal ball, that can all work. As long as you get the right one. Also for folks that use other identity pools (Facebook, etc) may deviate somewhat here. Be advised. But this is the way I got it for me (We don’t use any outside authentication sources):

You need an account ID:
This is your root AWS account ID. Not an IAM user. Not a cognito user. Your AWS console user ID. Found in “My Account” link under the drop-down named after my org. It’s all numbers. For me it was the org admin account, for you, it may be somebody specifically granted user rights to test your API. (Thanks to Raj for the clarification)

Identity Pool ID:
Navigate to it this way. AWS Console website -> Cognito -> Manage Identity Pool -> Select the proper identity pool -> Edit identity pool (top right for me) -> Identity Pool ID clearly visible. Broadly looks like: us-east-1:bcdfdf2-afdf-3b3c-3df4–4dcb-b6ee21b41c59

Your Cognito identity pool provider.
If you DON’T use Cognito identity pool this is another place where things will deviate. For Cognito identity pools you just piece it together (thank you random documentation somewhere).

cognito-idp.<aws region>.amazonaws.com/<User pool provider ID>
which means for me it was about:
cognito-idp.us-east-1.amazonaws.com/us-east-1_AabW32CD

Note that the user pool provider ID name is the name for me is my Cognito user pool, found conveniently in Cognito -> Manage user pools -> The user pool in question -> Pool ID right at the top of the “General settings”.

Now bringing it all together I put the account ID, identity pool ID, Cognito identity pool provider, and ID token that we got from the previous section, I compose the following JSON file (to make things easier):

{
“AccountId”: “YOUR AWS ACCOUNT ID (it should be numbers only!)”,
“IdentityPoolId”: “YOUR IDENTITY POOL ID”,
“Logins”: {
"YOUR IDENTITY POOL PROVIDER NAME”: “THIS IS YOUR ID TOKEN KEY just pasted here just like that eyJraWQiOiJ4Y0VBQ1fVDdjQzeHkJcU5uczdrb32Z0TXJ4eWw4NHVGXC9kZm9DTVk0YnpxWT0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI3NGI0YzkxYy1lYzViLTRiOWMtOWRmNS03OTdjMjEyZjIwMmIiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYWRkcmVzcyI6eyJmb3JtYXR0ZWQiOiIyIEF2ZSBSkZBMYWZheWV0dGUifSwiYmlydGhkYXRlIjoiMDNcLzA3XC8xOTg3IiwiZ2VuZGVyIjoM2MyZiIsImN1c3RvbTp6aXAiOiIwMjExMSIsInRva2VuX3VzZSI6ImlkIiwiYXV0aF90aW1lIjoxNTcxMDk1NDEyLCJwaG9uZV9udW1iZXIiOiIrMTYxNzg2MDM1MzkiLCJleHAiOjE1NzEwOTkwMTIsImlhdCI6MTU3MTA5NTQxMiwiZmFtaWx5X25hbWUiOiJEZXYiLCJlbWFpbCI6InRlc3QrZGV2X3VzZXIxQGdldGJyaW8uY29tIn0.S50sa8OKWXAsTtFTY6n1OLtAJmV3Qoy4dahBqMLfXE9lOW6Ckn-e79An3Lsioncz2HD6OhACoWTEDpSLvAMLqdCCpxPm5WX-bOVuu_YZ9y4Rf3ZmSFU_LZpyjPtX9IwwFkzumex4UTIR-5lrbZX6bZvZaqsNGGOIRzlEev9GWcmBVD2FzMblMF2Hhha3Ugk4xXKyGhjYEpz-Aoir1Rx5YORCag47IDz-_C2EDNXObaIn9Xkw-NX_3cd0g-aiyv_zSPnISaha3Q49yjTdPVpTdR7dD9PIkBeZxsCgdMjY4HfmhsLjWz9r82E8tFMSNL9yf3m8Fr5mOu7KNFczh5DPUq”
}
}

Now run this convenient command to finally get your identity ID:

$ aws cognito-identity get-id --cli-input-json file://get_id.json

More extensive documentation on get-id CLI is here: https://docs.aws.amazon.com/cli/latest/reference/cognito-identity/get-id.html

The fix part 3 — get your session information

This is the section where we’re finally going to pull the data that Postman needs to magically construct what’s called the AWS Signature V4 Header ( https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html), and thereby properly get blessed by the powers that be to execute API calls.

Using the information we already have from above create the following JSON file. The “Logins” section should be identical to the previous file you put together. I called this file get_credentials_for_identity.json.

{
“IdentityId”: “Your IDENTITY ID that you JUST GOT by running the previous command”,
“Logins”: {
"YOUR IDENTITY POOL PROVIDER NAME”: “YOUR SUPER LONG ID TOKEN”
}
}

Now use this file to get your session information:

$ aws cognito-identity get-credentials-for-identity --cli-input-json file://get_credentials_for_identity.json

This command (if everything is great) will yield three key pieces of information: access key ID, secret key, and the session token. It is also important to note that this stuff has a 1 hour expiration time, so FYI. With this information in hand we go to the most rewarding part:

The fix part 4 — Arming Postman with the authorization information

This part is relatively straightforward. I won’t go into the details of how to best use/configure Postman (primarily because I don’t actually know) but here are the barebones of what you need to make this work:

Set the authentication type for your API call/folder/collection/whatever to “AWS Signature.” This will show you the menu above. The {{user_access_key_id}}, {{user_secret_access_key}} and {{session_token}} map to the three pieces of information we extracted in the latest section. I use environment variables in Postman, you don’t have to. The keys are not to be confused with your IAM user’s access key and secret key. That could also work but not for API’s that require a Cognito logged in user to work. For any IAM_ROLE authorized API call we needed the end-user’s Cognito federated identity provided session information, not the IAM user’s.

Punch in that information into Postman and you should have a whole glorious hour of sending requests to your API. You can probably extend the token expiration date in one of the calls above, but that’s for another time.

Share and enjoy.

--

--