Tutorial AWS API Gateway + Cognito (UserPool) part two

FCavalcanti
5 min readJun 11, 2018

--

The purpose of this tutorial is to have three fully working routes, respectively for /login, /logout and /refreshToken using lambda functions, API Gateway, Cognito UserPool.

The motivation behind it was because all tutorials I’ve watched are either incomplete/did not match my needs, and since the official documentation is extense (and sometimes with holes on it) I deciced to create a ‘throughout’ tutorial gluing together all steps needed to have a fully working authentication API using APIGateway+Cognito+UserPool+CustomAuthorizer+LambdaFunctions!

Enjoy!!!

And remember to comment any missguided steps or doubts.!!!

Link to partOne!

Part two;
On this part of the tutorial we’re going to finish our existing authentication API with 2 more methods, one for refreshing accessToken and another to invalidate them. Plus another protected route with a CUSTOM authorizer (lambda method) that check’s also for accessToken invalidation as an valid workaround since the current API doest not fully invalidate the accessToken (by default they remain valid for 1 hour — check interesting links bellow for more info)

Let’s create all the lambda functions in a row and then create the respective apiGateway routes/methods to respectively signOut, refreshToken and finally a PROTECTED route so we can use the accessToken to validate requests!

1. Lambda triggers (functions)

  1. 1 — Create Function — Author from Scratch
    1.1.2 — Name the function ‘SignOUT’
    1.1.3 — Runtime — choose ‘python2.7’
    1.1.4 — You can choose the previously created role ‘lambda_sign_in’ but most likely the ‘lambda_basic_execution’ should be enough!!! I’ve choosen ‘lambda_sign_in’ because it’s guaranteed it will work!
    1.1.5 — Go ahead and download the function signOut.py from this gist (https://gist.github.com/fcavalcantirj/dd0aae0bddd9871e3e65e0cc5852059e) and Modify constants. USER_POOL_ID, CLIENT_ID and CLIENT_SECRET — as you’ve done in step 2.1.2 of the Part_ONE of this tutorial.
    1.1.6 — Copy and past the contents of signOut.py on the webEditor
    1.1.7 — Click Save
    1.1.8 — Click ‘Select Test Event’ and then ‘Configure Test Events’ and name it ‘SignOUTTest’ and modify json to look as above
    *****CODE*****
{
"access_token":"theAccessToken…"
}

*****END_CODE*****
ps; this acessToken was just generated using the PUT /auth route created on PartOne.
1.1.9 — Click ‘Create’ -> click ‘Test’ and make sure your execution logs look like above;
*****LOG*****

{
"message":"Usuario deslogado com sucesso"
}

*****END_LOG*****
ps; this means that the user was logged out successfully!

{
"access_token":"theAccessToken…"
}

*****END_CODE*****
ps; this acessToken was just generated using the PUT /auth route created on PartOne.
1.1.9 — Click ‘Create’ -> click ‘Test’ and make sure your execution logs look like above;
*****LOG*****

{
"message":"Usuario deslogado com sucesso"
}

*****END_LOG*****
ps; this means that the user was logged out successfully!

ps2; this accessToken is still valid for requests, as it is described here (http://awsfeed.com/post/170845002029/aws-cognito-user-pool-access-token-invalidation) -> we will deal with this later on this turorial with a workAround approved by AWS.

  1. 1.10 — Note that if you click ‘Test’ again the response logs should be;
    *****LOG*****
{
"status":"fail",
"msg":"The accessToken is invalid"
}

*****END_LOG*****
This is correct as the accessToken is ‘invalid’ from the server-side perspective, but still active for requests — again, we will deal with this later on this tutorial.

1.2 — Create Function — Author from Scratch
1.2.1 — Name the function ‘RefreshTOKEN’
1.2.3 — Runtime — choose ‘python2.7’
1.2.4 — You can choose the previously created role ‘lambda_sign_in’ but most likely the ‘lambda_basic_execution’ should be enough!!! I’ve choosen ‘lambda_sign_in’ because it’s guaranteed it will work!

  1. 2.5 — Go ahead and download the function refreshToken.py from this gist (https://gist.github.com/fcavalcantirj/f7ff842706d64eb6fdb40bf02fa6f44b) and Modify constants. USER_POOL_ID, CLIENT_ID and CLIENT_SECRET — as you’ve done in step 2.1.2 of the Part_ONE of this tutorial.
    1.2.6 — Copy and past the contents of refreshToken.py on the webEditor
    1.2.7 — Click Save
    1.2.8 — Click ‘Select Test Event’ and then ‘Configure Test Events’ and name it ‘refreshTokenTest’ and modify json to look as above
    *****CODE*****
{
"refreshToken":"theRefreshToken…."
}

*****END_CODE*****

1.3 — Create Function — Author from Scratch
1.3.1 — Name the function ‘CustomAuthorizer
1.3.2 — Go to this link — https://aws.amazon.com/pt/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/
1.3.3 — Under the section ‘Develop a Custom Authorizer for Amazon Cognito User Pools’ — follow the steps 1 to 4! (not the first section with dynamo involved)
ps. basically you’ll download a zip file, open it, alter the code, zip again and upload as a new lambda function to be used as a customAuthorizer on the API Gateway

2. Api Gateway

We will create 2 more methods on the existing /auth route. One for tokenInvalidation (signOut) and other to refreshToken. Then we will create another resource (protected with a custom authorizer) to demonstrate how we can authenticate requests using the accessToken generated on the first part of this tutorial!

2.1 — Create another method (DEL) and assign a lambda function (SignOUT step 1.1) as the request integration
2.2 — Create another method (POST) and assign a lambda function (RefreshTOKEN step 1.2)
2.3 — Create another resource (/protected) and create a GET method -> we’re going to stop and create the custom authorizer now, so we can use this customAuthorizer on this method. In case you have doubs on how to create this authorizer folow the steps 5 and 6 on this link (https://aws.amazon.com/pt/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/)
2.4 — With the custom authorized created, go back to the GET method under the /protected route, set the integrationType to ‘Mock’, go to the ‘MethodRequest’ -> ‘Authorization’ -> and choose the recently created customAuthorizer

Remember to ALWAYS redeploy your API to test it!!!

And that’s it!!! Now we have a resource called /auth with 3 methods (PUT, POST and DELETE) [signIn, refreshToken and signOut respectively] and another resource called /protected with a GET method (mocked) used just to demonstrate how we can authenticate requests using the accessToken. Enjoy!!!

I’m going to write couple curl’s requests to demonstrate all together.

SignIN -> Open up terminal and execute -> curl -v -XPUT -H “Content-type: application/json” -d ‘{“username”: “admin”,”password”: “x*F-6q8@”}’ ‘https://yourDeployedAPIGatewayURL/dev/auth'

SignOUT -> Open up terminal and execute -> curl -v -XDEL -H “Content-type: application/json” -d ‘{“access_token”: “theAccessToken”}’ ‘https://yourDeployedAPIGatewayURL/dev/auth'

RefreshToken -> Open up terminal and execute -> curl -v -XPOST -H “Content-type: application/json” -d ‘{“refreshToken”: “theRefreshToken”}’ ‘https://yourDeployedAPIGatewayURL/dev/auth'

ProtectedRoute -> Open up terminal and execute -> curl -XGET -H ‘Authorization: *validAccessTokenHERE*’ ‘https://yourDeployedAPIGatewayURL/dev/protected'

Known problems

1. If ou hit the SignIN method with an not existent login the error will be
*****CODE*****

{
"status":"fail",
"msg":"Unknown error"
}

*****END_CODE*****
Which is ugly — we should provide a better error.
2. If you hit the SignIN method with an existent (but not validated) user (with an status FORCE_CHANGE_PASSWORD) for example, the error will be even worse (exception occurs)

And other stuff like validate parameters on the lambda side, etc… this tutorial is not a *production ready* authentication, but a very good starting point for developers that wan’t this kind of authentication on their project.!

Any problems or doubts, improvements, just comment it.

--

--