This is a guest post by Pius Aboyi. If you want to learn more about how to manage sessions with refresh tokens, read this blog. If you don’t want to have to write all this code, you can simply use Passage to integrate passwordless authentication into your app, and have them handle all the details for your app.
A common flow for API authentication is the sending of data to an endpoint that verifies a user. Once verification is successful, the API will return an access token that you can then use to make requests to other endpoints that require authorization. In addition to an access token, most APIs also return a refresh token. In this post, you'll learn what refresh tokens are and how they work.
A refresh token is a special key that enables a client for an API or service to retrieve new access tokens without requiring the user to perform a complete login. In other words, an application can exchange a valid refresh token for a new access token. In addition to the new access token, the service may return a new refresh token too.
Why do refresh tokens matter, and does a client need to exchange them for a new access token? The main reason why refresh tokens exist is because most access tokens don't live forever. That is to say, an access token may expire after a specific period of time like a few hours or days. Hence, in order to avoid requesting that the client perform an activity like entering a username and password to retrieve a new access token, you can use refresh tokens to get a new access token.
Refresh tokens matter a lot because they can improve the user experience and the general security of an application. On the side of user experience, imagine forcing your users to log in every time they return to your application after the access token expires. Most popular services seamlessly allow users to return to their previous session by silently generating new access tokens using refresh tokens.
To answer the above question, let me explain further why access tokens usually have an expiration time. In a situation where a malicious user gets a hold of a valid access token, they can make requests on behalf of a user and access protected data. As a result, access tokens expire after some time and become invalid. Refresh tokens, on the other hand, live longer so that your application can make use of it to retrieve a new access token. In order to increase the security of your application, you should avoid exposing refresh tokens.
A secure way to send refresh tokens back to a client application is through HTTP-only cookies.
In this section, we'll take a closer look at how refresh tokens work. We'll do this by reviewing the various stages of API authentication and authorization.
The first stage involves the user logging in to an API service. This could be done by sending an HTTP request with a username and password. Then, on successful authentication, the API returns an access token (for example, a JWT).
The following code snippet shows the implementation of an API login endpoint:
In the above code, the duration for the access token is five minutes. Hence, this token will expire and no longer work after five minutes.
Now that we have a valid access token, we can proceed to make a request on behalf of a user. A protected endpoint is an endpoint that requires the user to be logged in to fetch or write data. A good example is an endpoint that returns the current user's profile.
Here's an example that enables the user of the access token to query for their profile:
In Stage 1 above, I mentioned that the access token will expire after five minutes. So, in order to retrieve a new token after that happens without repeating Stage 1, you can send a request to another endpoint to renew the access token.
The following code contains the logic for this refresh endpoint:
Usually, during the first stage of the authorization process, the system generates a token after a successful login. Then the system returns the new refresh token along with the access token, and it remains valid for a longer duration than the access token.
You do not need the refresh token in order to access protected endpoints. After the access token expires, you can send another request using the refresh token to request a new access token.
Finally, once a user intentionally revokes access to their session, both the access token and its associated refresh token are rendered invalid and useless. Hence, sending a request for a new access token using such a refresh token will return an error.
Refresh tokens and access tokens serve very different purposes in the authorization process. In this section, we'll take a look at some of their differences and similarities.
Access tokens enable APIs to determine who is requesting what resource and whether they have the necessary permissions. Refresh tokens, on the other hand, are unable to do this directly. You'll first need to exchange a refresh token for a valid access token that you can then use to access the resources.
Ideally, access tokens expire after a short period, whereas refresh tokens live for a long time.
Both refresh and access tokens can be generated using the JSON Web Tokens (JWT) standards. Using this method, the token encodes some data that you can specify as a payload. It's possible to decode this token and get back the original data that was encoded. For example, a token may contain the username, session ID, and email address of the current user. However, it is bad practice to include sensitive information like passwords in tokens.
In this post, we covered what refresh tokens are and how they work. We described them as keys that your application can exchange for new access tokens. A major job of the refresh token at a high level is to keep users signed in for a longer time and prevent them from having to manually log in every time they want to access your app.
We also mentioned that refresh tokens and access tokens are different in multiple ways. For example, refresh tokens live longer than access tokens. And finally, you can't use refresh tokens in place of access tokens to read or write data on a protected endpoint.
This post was written by Pius Aboyi. Pius is a mobile and web developer with over 4 years of experience building for the Android platform. He writes code in Java, Kotlin, and PHP. He loves writing about tech and creating how-to tutorials for developers.