Why Do We Need Token Refresh?
Imagine you're playing an online game, and every 30 minutes, you get kicked out and have to log in again. Frustrating, right? In web applications, authentication works similarly. Tokens (like digital passes) expire for security reasons, but we want to make this process smooth for users.
The Problem with Traditional Authentication
When a token expires, most applications force you to log in again. This is like being midway through a task and suddenly being told to start over from scratch. Our goal is to fix this!
How Token Refresh Works: A Simple Explanation
Think of Tokens Like a Day Pass
- Access Token: A short-lived ticket that lets you enter different parts of an application
- Refresh Token: A special, longer-lasting ticket that helps you get a new access token
The Magic Happens in Two Steps
Step 1: Detect Token Expiration
// When a request fails because the token is old
Client.interceptors.response.use(
(response) => response, // Normal responses pass through
async (error) => {
// Check if the error is because the token is expired
if (error.response?.status === 401) {
// It's like saying, "Oops, my pass is old. Let me get a new one!"
const newToken = await refreshToken();
}
}
)
Step 2: Get a New Token
const refreshToken = async () => {
try {
// Ask the server for a new access token
const response = await Client.post("/auth/refresh", {
withCredentials: true // Important security detail
});
// Extract the new token
const { accessToken } = response.data;
// Update the application with the new token
updateToken(accessToken);
return accessToken;
} catch (error) {
// If getting a new token fails, log the user out
console.error("Couldn't refresh token");
return null;
}
};
The Secret Sauce: Remembering the Original Request
// This is the magical part - saving the original request
const originalRequest = error.config;
// After getting a new token, replay the exact same request
if (newToken) {
// It's like rewinding and replaying a game level
originalRequest.headers.Authorization = `Bearer ${newToken}`;
return Client(originalRequest);
}
Real-World Analogy
Think of this like a multi-pass at an amusement park:
- Your access token is a single-ride ticket
- Your refresh token is the ability to get a new ride ticket
- When a ride ticket (access token) expires, you use the multi-pass (refresh token) to get a new one
- You don't have to leave the park or start over - you just get a new ticket!
Backend: Verifying the Refresh Token
const refresh = async (req, res) => {
try {
// Check if the refresh token exists
const refreshToken = req.cookies.refreshToken;
// Verify the token is valid and belongs to a real user
const payload = jwt.verify(refreshToken, process.env.JWT_SECRET);
// Find the user
const user = await User.findOne({ email: payload.email });
// Create a new access token
const accessToken = jwt.sign({
username: user.username,
email: user.email
}, process.env.JWT_SECRET, { expiresIn: "1d" });
return res.status(200).json({ accessToken });
} catch (error) {
// Something went wrong
return res.status(401).json({ message: "Authentication failed" });
}
};
Key Takeaways
- Token refresh keeps users logged in seamlessly
- We save the original request to replay it after getting a new token
- The process happens automatically in the background
- Users never know their token was refreshed
Pro Tips
- Always use HTTPS to protect tokens
- Implement proper error handling
- Have a backup plan if token refresh fails
Conclusion
Authentication doesn't have to be complicated. With the right approach, you can create a smooth, secure experience that keeps your users happy and your application protected.
Happy Coding! ππ
Top comments (0)