Refresh tokens allows you to issue short-lived access tokens and longer-lived refresh tokens. When the access token expires, the client can send the refresh token to get a new access token. This provides an additional layer of control for logout or token expiration.
- Access Token: Short-lived (e.g., 15 minutes), used to access protected resources.
- Refresh Token: Long-lived (e.g., 30 days), used to request new access tokens after expiration.
Refresh Token Flow:
- User Logs In:
- The server sends both an access token (JWT) and a refresh token.
- User Logs Out:
- The client removes both the access token and refresh token.
- The server can invalidate the refresh token (e.g., remove it from the database).
- Access Token Expiry:
- When the access token expires, the client can use the refresh token to obtain a new access token from the server.
This approach allows for more robust logout functionality, as refresh tokens can be invalidated server-side, ensuring that the user can't continue using old tokens.
2.Why Use Refresh Tokens?
Refresh tokens help youseparate concerns of authentication (verifying a user's identity) and session management (keeping a user logged in over time) while maintaining security.
Key Benefits:
Short-Lived Access Tokens (Access Control):
- If the access token is short-lived (e.g., 15 minutes), it limits the exposure time of an access token.
- If an attacker steals the access token, the damage is limited by its short lifespan.
Long-Lived Refresh Tokens (Reauthentication):
- Refresh tokens allow the user to stay logged inwithout needing to authenticate again after the access token expires.
- Refresh tokens are keptsecurely (on the client side, usually in anhttpOnly cookie), and only sent to the server when a new access token is needed.
3.How the Client Handles Refresh Tokens
Here's the flow for handlingrefresh tokens on the client side, assuming you're using JWTs.
Login Flow:
- User logs in with their credentials (email + password).
The server responds with:
- Access Token (short-lived, e.g., 15 minutes)
- Refresh Token (long-lived, e.g., 30 days)
The client stores:
- Theaccess token (e.g., in memory, localStorage, or a cookie for API calls).
- Therefresh token (preferably in anhttpOnly cookie, which is less vulnerable to XSS attacks).
Requesting New Access Token with Refresh Token:
- When the client makes a request to a protected route, it includes theaccess token in the
Authorization
header. - If the access token expires, the client will send therefresh token to the server to get a new access token:
- The server verifies therefresh token.
- If valid, the server issues a newaccess token and sends it back to the client.
- The server may also refresh therefresh token itself, issuing a new one with each access token renewal (to prevent long-term use of an old refresh token).
Logout Flow:
- Tolog out, the client can:
- Remove both theaccess token andrefresh token from the client (i.e., fromlocalStorage orcookies).
- Optionally, the client can notify the server toinvalidate the refresh token (by blacklisting or removing it from the database).
4.How to Implement Refresh Tokens on the Client-Side
Here’s how you would manage therefresh token on the client side, usinglocalStorage,sessionStorage, orhttpOnly cookies.
1.Storing the Tokens
Access Token:
- You may store it inlocalStorage orsessionStorage to make it easily available for API requests. However, this could expose the token toXSS attacks if the site is vulnerable.
- Alternatively, you can store it inmemory (in a JS variable) while the app is running (but this means the user will need to log in again if the page is refreshed).
Refresh Token:
- httpOnly cookies are the most secure option for storing refresh tokens, as it prevents access to the refresh token via JavaScript (protecting from XSS attacks).
- Example:
Set-Cookie: refreshToken=<value>; HttpOnly; Secure; SameSite=Strict
.
2.Making API Requests with the Access Token
For each request to a protected route, you send theaccess token in theAuthorization
header:
fetch('https://api.example.com/protected',{method:'GET',headers:{'Authorization':`Bearer${accessToken}`,// Attach the access token},}).then(response=>response.json()).then(data=>{// Handle the API response}).catch(error=>{// Handle errors});
3.Handling Access Token Expiry and Refreshing
If theaccess token expires, you can request a new one by using therefresh token.
- First, check if the access token has expired.
- If expired, send a request to your backend to refresh the token.
Example refresh token request:
// Function to get a new access token using refresh tokenfunctionrefreshAccessToken(){returnfetch('https://api.example.com/refresh',{method:'POST',body:JSON.stringify({refreshToken}),headers:{'Content-Type':'application/json',},}).then(response=>response.json()).then(data=>{const{accessToken,refreshToken:newRefreshToken}=data;// Store the new tokens (in memory, localStorage, etc.)storeTokens(accessToken,newRefreshToken);}).catch(error=>{// Handle error, e.g., if refresh token is invalid or expired});}
4.Removing Tokens on Logout
To log out, you simply remove both theaccess token andrefresh token from wherever they are stored:
// Remove from localStoragelocalStorage.removeItem('accessToken');localStorage.removeItem('refreshToken');// Remove from cookiesdocument.cookie='refreshToken=; Max-Age=0; path=/;';
5.Server-Side: Handling Refresh Tokens
When the client sends arefresh token to get a new access token, the server will:
- Verify the refresh token (check its signature, expiration, etc.).
- If valid:
- Issue anew access token.
- Optionally issue anew refresh token.
- If the refresh token is expired or invalid, deny the request and require the user to log in again.
Example Express Route for Refreshing Tokens:
// src/routes/refreshTokenRoute.tsimportexpressfrom'express';import{verifyRefreshToken,generateAccessToken}from'../utils/jwtUtils';import{getRefreshTokenFromCookies}from'../utils/cookieUtils';constrouter=express.Router();router.post('/refresh',async(req,res)=>{constrefreshToken=getRefreshTokenFromCookies(req);if(!refreshToken){returnres.status(401).json({message:'Refresh token missing'});}try{constuser=awaitverifyRefreshToken(refreshToken);// Verify refresh tokenconstnewAccessToken=generateAccessToken(user.id);// Generate a new access tokenconstnewRefreshToken=generateRefreshToken(user.id);// Optionally, generate a new refresh tokenres.json({accessToken:newAccessToken,refreshToken:newRefreshToken,// Optionally send the new refresh token});}catch(error){res.status(403).json({message:'Invalid refresh token'});}});exportdefaultrouter;
Conclusion
Refresh tokens provide a more secure and flexible approach for managing long-lived user sessions in a stateless authentication system. They allow you to:
- Keepaccess tokens short-lived for security (limiting exposure if the token is stolen).
- Userefresh tokens to request new access tokens without requiring the user to log in repeatedly.
- Ensurelogout by simply removing both tokens from the client-side storage.
This separation betweenaccess tokens andrefresh tokens gives you more control over security and user experience.
What are your thoughts😊?
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse