How Tokens Work in Amazon Cognito User Pools
Adam C. |

AWS provides us Amazon Cognito User Pools, which could be used as authorizer to control access to our application. Per Amazon Doc:  Amazon Cognito user pools implement ID, access, and refresh tokens as defined by the OpenID Connect (OIDC) open standard:

  1. The ID token contains claims about the identity of the authenticated user such as name, email, and phone_number.
  2. The access token contains scopes and groups and is used to grant access to authorized resources.
  3. The refresh token contains the information necessary to obtain a new ID or access token.

When we sign in the user pool using Amplify, we will obtain all those three tokens. 

Photo by Genessa Panainte on Unsplash

Which Token to Call API?

Normally, the ID token is for Authentication, and the access token is for Authorization. When calling the API method, we typically set the token to the request's Authorization header. So, it sounds like we should use the access token, doesn't it? Based on the doc, we could use either the ID token or the access token. However,  as we tested, we should use the ID token. That's because:

  1. The ID token is used to authenticate users to our resource servers or server applications (ex: API)
  2. The purpose of the access token is to authorize API operations in the context of the user in the user pool. For example, you can use the access token to grant your user access to add, change, or delete user attributes.

What's the Refresh Token?

Usually, we set the access token/the ID token expiration to be much shorter than the refresh token expiration. And then when the access token/the ID token expires, we can use an unexpired refresh token to get a new access token/ID token without asking users to re-login. The reason behind this is that the access token/the ID token is used to API method, in case they are stolen, the short expiry time could help minimize the damage. 

Will the Refresh Token Expires?

Yes, with Amazon Cognito User Pool, we can set the app's refresh token expiration to any value between 60 minutes and 10 years. 

How to Check if the Refresh Token Expired or Not?

Different to the access token/the ID token, which is the JWT token where we can get the expiration date, we cannot tell if the Refresh Token Expired or not from the token. But we can tell it from the auth_time of the refresh token/the ID token. For example, we set the refresh token expiration to 1 day, then we can use the following equation to get the refresh token expiration DateTime:

const authTime = user.signInUserSession.accessToken.payload["auth_time"];
const refreshTokenExpirationTime = 
	new Date(authTime * 1000 + 24 * 60 * 60 * 1000)

Possible Issues When Refresh Token is Expiring

We set the access token expiration to be 60 mins, and the refresh token expiration to be 1 day. We use the Amplify library, which auto-refreshes the token when the access token expires, we basically get the 1-day session duration. Note that when the refresh token expires, the user has to re-login to get the new access token, ID token, and refresh token. So if the user is working on something when both the ID token and the refresh token are expired, then the unsaved work will be lost.

To understand how this works, let us use an example:

  • The user logged in today at 9:00 am, he got an accessToken (valid until 10:am) and a refresh token (valid until 9 am tomorrow)
  • He comes back at 10:30 am, and his access token expires, but he is still logged in because his session is refreshed by the refresh token and he gets the new access token (valid until 11:30 am) and his refreshToken is still valid until 9 am tomorrow.
  • He comes back tomorrow at 8:30 am, he is still logged in, again thanks to the refresh token, and he gets a new access token valid until 9:30 am, then there is an issue because at 9:31 am, he has to re-login since his refresh token will be expired at that time. So his unsaved work will be lost at 9:31 am.

How to Handle When Refresh Token is Expiring

If your application has an auto-save feature, like Gmail App, then how the refresh token works as we discussed above should be fine. Otherwise, we may look into some solution to manually log out the user at the right time to avoid losing unsaved work.

Solution One

Log out the user when the refresh token is about to expire in 60 mins, and we can check this when the page loads and when the user is active right after idle. In the other words, if the refresh token is not expired in 1 hour, then the user could get one more refresh, which could mitigate the session losing. 

Solution Two

Implement the strict mode, for example, log out the user after the idle time is more than  15 mins, which could be a popup to allow the user to extend the session (by setting a longer refresh token expiration.) Also, log out the user when we detect the refresh token expiration time is in a day at the initial page load. But this solution will sacrifice the benefit of the refresh token.

We know both solutions are not great. So if you have any ideas, please leave your comments.