Search code examples
amazon-web-servicesaws-api-gatewayamazon-cognito

What do I do with the authentication tokens passed back from cognito user pools?


Alright, I am in the process of setting up user sign-in / sign-up with AWS Cognito. After a user is signed in I want to give them access to call an API I have built with API gateway.

I've already set up the cognito user pool, Api (with cognito user pool authorization), and lambda functions. I am now trying to log in to a web application by passing the test users username and password. This currently does work and I get back the access token, id token, and refresh token from cognito. I have also been able to call the API by passing the ID token with the authorization header to API gateway. I am not trying to implement MFA (for now) so the only method call to the AWS SDK I am doing is the InitiateAuthCommand https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/cognito-identity-provider/command/InitiateAuthCommand/ which passes back the tokens if the user entered the correct username and password.

My question now is, what do I do with the tokens? Am I supposed to store these in local storage so that the application can access them for route protection and log the user out of the application when they expire? This is my first time doing something like this and I would like to get it right.

The AWS docs have been a big help so far in getting set up, but they don't really say what you should do with the tokens passed back from Cognito other than having your application handle them. Obviously, aside from giving the user the ability to call this API I have built, I would like to let the user login to the application if a token was passed back from cognito so I am thinking I would have to store them in local storage or some kind of state variable and then apply some logic to expire / refresh them and let the user access specific routes?

Can someone shed some light on this, please, I feel like I've made it quite far, but I need a little extra help in understanding this to get over the hump.

Auth Flow -> user accesses sign-in / sign-up page -> user enters username and password -> cognito tokens are passed back to the client -> ID token is passed to the authorization header of the API gateway call to let the user hit the endpoint.

EDIT: I placed the tokens in a state variable after validating them. This works, but I don't really know if this is the correct way to store them


Solution

  • You've done a great job implementing the backend setup for login and token retrieval. Based on your description, there are two main concerns you have:

    1- How to store the Cognito tokens?

    Storing the user tokens in a web application can be considered a whole another topic. But there are two popular and good practices:

    Local Storage: You can store the tokens in the local storage of the browser. This is a common practice, but be aware that it may expose tokens to cross-site scripting (XSS) attacks. With other measures in place this is a viable approach. For example AWS Amplify's Javascript SDK uses local storage to store the cognito tokens by default.

    Session Storage: This is similar to local storage but is cleared when the session ends (i.e., the browser is closed). This could be a more secure option if you want the tokens to persist only during an active session.

    State Variable (In-Memory Storage): Storing tokens in a JavaScript variable (in-memory storage) means the tokens are lost when the page is refreshed which is not very practical in terms of user expreience and might require you to make very frequent token retrieving api calls.

    You can simply choose local storage if you want persistence across browser sessions or session storage if this is not a concern.

    2- What to do when tokens expire?

    Handling token expiration typically involves using a refresh token. In your case, AWS SDK can facilitate this.

    A common strategy is to refresh the ID token upon making an API call if the current token has expired. Implement this by detecting an expired token response, refreshing the token, and then retrying the initial API call.

    Regarding user logout it's not standard practice to log out users immediately upon token expiration. Many web applications allow users to remain logged in during short periods of inactivity (given the typically short lifespan of JWT's). For most cases you might not even want to log out the user unless it is explicit request of the user. If you want to implement immediate logout without user command this often involves additional logic based on user actions, time intervals, device types etc. For simplicity, you might choose to address this later, based on your specific requirements.