How to Process an AWS Cognito Authorization Code Grant using AWS Amplify

Most developers that work with AWS Cognito let Amplify process the authorization code grant. However, if you're developing a mobile JavaScript app with Social Sign-On you may need to process the code grant yourself. Here's how...

How to Process an AWS Cognito Authorization Code Grant using AWS Amplify
Photo by FLY:D / Unsplash
Rover

Most developers that work with AWS Cognito + Amplify take advantage of the built-in urlListener within Amplify which automatically processes a Cognito web response containing an authorization code grant. However, if you’re building a mobile JavaScript application and want to offer Social Sign-On, you may need to process the code grant yourself if Deep Links aren’t an option for handling your redirect. We’re doing a big overhaul on the Corkhounds.com mobile app, and we were recently faced with this situation. It’s not intuitive how to programmatically process an authorization code grant, and it takes a lot of digging around online to figure it out. If you are curious how this works, this post is for you.

Assumptions and Overview

We assume you are already using AWS Cognito and Amplify and that you already have a Cognito User Pool. Getting up and running with Cognito and Amplify is a topic all on its own. We also assume you are using the authorization code grant response type, and that you are successfully using Amplify’s Auth.federatedSignIn() method with Facebook, Google, or Apple Social Sign On or the Hosted UI. You should be receiving a Cognito web response with an authorization code grant that looks similar to:

https://YOUR_APP_URL/redirect_uri?code=AUTHORIZATION_CODE&state=STATE

We will start by showing you how to parse this web response using the Ampify Authentication module, and walk through one way of creating a Cognito User Session, and finally how to get Amplify to pick up / recognize that session and showing that user as currently authenticated.

Processing the Code Grant

When you search the web for ways to parse the Cognito web response, you will undoubtedly find lots of references to the amazon-cognito-auth-js package and the parseCognitoWebResponse() method.  However, the original amazon-cognito-auth-js package has been archived by Amazon, and Amplify's Authentication module took over.  There is no parseCognitoWebResponse() in the Amplify codebase, so it would seem this feature is no longer supported.

Luckily, there is an example for processing the Cognito web response containing the authorization code grant to retrieve the access, id and refresh tokens. Amplify's Auth._oAuthHandler.handleAuthResponse() parses and submits the code grant against the oauth2/token endpoint to retrieve the tokens.   You can review the code in Amplify's github repo to see how it works. Unfortunately, the _oAuthHandler function is marked private in TypeScript.   If you're not using TypeScript, you can use this function, but that's dangerous given that the development team could make changes in a future release.  I have submitted a feature request to have this function made public, but it hasn't been answered as of yet.

I'll show you how it works, but proceed at your own risk. First we will need to install the amazon-cognito-identity-js package, and its dependency, the aws-sdk:

npm install aws-sdk amazon-cognito-identity-js

Let’s step through the code sample below. I’ve nested comments throughout this sample to explain what we’re doing in each step. You should already have imported both Amplify and the Auth module. And for simplicity, we’ll import all the modules from the amazon-cognito-identity-js package. Since you already have Amplify and Auth configured (based on our assumptions above), we can now use the Auth._oAuthHandler.handleAuthResponse() method to process the cognito web response url. We'll then parse the response to create an CognitoAccessToken, CognitoIdToken and CognitoRefreshToken. Using these tokens, we can then create a CognitoUserSession.

At this point, we have a Cognito user session, but it is not recognized by Amplify yet.  If you were to run the Auth.currentAuthenticatedUser() method now, you would find that there is no authenticated user.   The principal reason for this seems to be because the session/tokens aren't stored in a place where Amplify picks them up. You can read more about this in Amplify's GitHub issue #6555.  

Creating the Amplify Authenticated User Session

Now that we have a Cognito User Session, we need to tell Amplify about it.  The easiest way I found to do this is documented on Amazon Cognito's web documentation, and I'll break it down here. Like before, I’ve nested comments throughout this sample to explain what we’re doing in each step.

Essentially the steps are to create a CognitoUserPool object, and then we can use that with the user's username contained in the accessToken to instantiate a CognitoUser.  With the CognitoUser object in hand, we can call the setSignInUserSession() method using the CognitoUserSession we created earlier to finish creating the Amplify user session.  

Now, Amplify will return the authenticated user correctly.  If you're like me, you would think there should be an easier way to achieve this result – given that Amplify/Auth are already configured, and you have the CognitoUserSession separately – and there might be.  But I haven't found it yet.

Putting it all together

Now we will stitch all the code together for simplicity.

Conclusion

Hopefully you found this blog useful for turning an authorization code grant into an Amplify authenticated user.  Feel free to reach out with any questions.