Welcome to the first lesson of our course on securing your REST API application with TypeScript. In this lesson, we will focus on implementing and rotating refresh tokens.
Refresh tokens are long-lived credentials that allow clients to obtain new access tokens without requiring the user to re-authenticate. While access tokens are short-lived (typically minutes) and grant access to protected resources, refresh tokens have a longer lifespan (days or weeks) and are used solely to obtain new access tokens when the current ones expire.
The main purposes of refresh tokens include:
- Improving User Experience: Users don't need to login repeatedly
- Enhancing Security: Access tokens can be short-lived, limiting the damage if compromised
- Maintaining Sessions: Applications can maintain user sessions across restarts or network changes
Advantages:
- Reduces the frequency of user authentication
- Allows for shorter-lived access tokens, improving security
- Enables token revocation without affecting the authentication flow
- Supports proper logout functionality by invalidating tokens
Disadvantages:
- Increases complexity of the authentication system
- Requires server-side storage and management
- Can be vulnerable to theft if not properly secured
- Adds additional API calls to the authentication flow
Refresh token rotation is a critical security practice where each refresh token can only be used once. Let's clarify how it works:
-
What is token rotation? When a client uses a refresh token to get a new access token, they also receive a new refresh token simultaneously, and the old refresh token becomes invalid.
-
The rotation flow:
- Client sends the current refresh token to get a new access token
- Server immediately invalidates the sent refresh token
- Server generates and returns both a new access token AND a new refresh token
- Client must use the new refresh token for future refreshes
-
Security benefits:
- Creates a rotating chain of tokens that are each used exactly once
- If a refresh token is stolen and used by an attacker, the legitimate user's next refresh attempt will fail
- This failure serves as an early warning system for token theft
- Limits the "window of opportunity" for attackers to use a stolen token
This approach differs from simple refresh mechanisms where the same refresh token can be used multiple times, which creates a longer vulnerability window if the token is compromised.
By the end of this lesson, you will be able to implement refresh tokens, create authentication tokens, and handle token rotation securely.
The diagram above illustrates the complete flow of token rotation when a client requests new tokens using the /refresh
endpoint. Let's walk through each step to understand how our secure token rotation system works in practice:
The Token Rotation Process:
-
Client Initiates Refresh: The client sends a POST request to
/refresh
with their current refresh token (refreshToken₀
) -
Database Lookup: The API searches the database for the provided refresh token to verify its validity
-
Validation Check: The system evaluates the token status:
- If the token is missing or expired, the flow immediately returns a 401 Unauthorized error
- If the token is valid, the rotation process continues
-
Immediate Token Invalidation: Before generating new tokens, the API deletes the used refresh token from the database. This is the critical security step that ensures each token can only be used once
-
New Token Generation: The system creates both:
- A new short-lived access token (
accessToken₁
) - A new refresh token (
refreshToken₁
) for future refreshes
- A new short-lived access token (
-
Persistence: The new refresh token is stored in the database with its expiration date
-
Client Response: Both the new access token and refresh token are returned to the client, completing the rotation cycle
Security Benefits of This Flow:
This sequence demonstrates our single-use token policy in action. Notice how the old token is immediately invalidated (step 4) before new tokens are created. This ensures that:
- Any token can only be used exactly once
- If a token is compromised and used by an attacker, the legitimate user's next refresh attempt will fail
- The system maintains a complete audit trail of token usage
The diagram also shows the alternative flow (step 3) where invalid or expired tokens result in an immediate 401 response, preventing any further processing and maintaining system security.
Let's implement the RefreshToken
model that will store our tokens in the database:
Code Logic: This model creates a database table to track refresh tokens. The key design choices here are:
- Using the token itself as the primary key for fast lookups
- Storing a reference to the user who owns the token
- Including an expiration date to automatically invalidate old tokens
- Not storing access tokens in the database since they're self-contained JWTs
Next, we implement the function that generates both access and refresh tokens:
Code Logic:
- The access token is a JWT with a short lifespan (15 minutes) that contains the user ID and a unique token ID
- The refresh token is a simple UUID with a longer lifespan (7 days)
- Before creating a new refresh token, we delete any existing tokens for that user, implementing a "one token per user" policy
- Both tokens are returned to the client, but only the refresh token is stored in the database
This approach ensures that a user can only have one valid refresh token at a time, which simplifies token management and enhances security by making it easier to detect token abuse.
The /refresh
endpoint is where token rotation happens:
Code Logic: This is the core of our token rotation implementation:
- Verify the incoming refresh token exists in our database
- Check if the token has expired
- Immediately delete the used token from the database
- Generate a new access token and refresh token pair
- Store the new refresh token in the database
- Return both tokens to the client
This rotation mechanism is crucial for security because:
- It ensures each refresh token can only be used once
- If a token is stolen and used by an attacker, the legitimate user's token becomes invalid
- This invalidation alerts the user to potential token theft when their app suddenly requires re-authentication
Key Error Handling Aspects:
- We immediately fail with appropriate error codes if tokens are missing or invalid
- Expired tokens are automatically removed from the database
- Database errors are caught and don't expose internal details to clients
- Each error response includes a specific message to help debug client-side issues
In this lesson, we covered the implementation and rotation of refresh tokens in a TypeScript-based REST API. You learned what refresh tokens are, their advantages and disadvantages, and how to implement a secure token rotation system.
The key security concepts we've implemented are:
- Short-lived access tokens with longer-lived refresh tokens
- One refresh token per user policy
- Single-use refresh tokens with rotation
- Proper token validation and error handling
As you move on to the practice exercises, focus on applying what you've learned to reinforce your understanding. This is just the beginning of your journey in securing your REST API. Keep exploring the course to enhance your skills and protect your API from unauthorized access and abuse. Good luck!
