Building a Secure Authentication Flow Using Refresh Tokens in Node.js and Next.js
Prashanth S
Software Architect & Tech SME @ Quantiphi | AI Enthusiast | SaaS Builder | Tech Strategist | GCP Expert
Authentication is a cornerstone of web development. From e-commerce to SaaS platforms, providing secure, seamless, and scalable authentication is critical. In this article, we’ll explore how to implement a secure authentication flow using refresh tokens in Node.js and Next.js, ensuring the safety of user sessions while maintaining an optimal user experience.
Understanding Access and Refresh Tokens
Tokens are widely used in modern authentication systems, especially for Single Page Applications (SPAs) and mobile apps.
Access Tokens
Refresh Tokens
Why Token Security Matters
Without proper safeguards, tokens can be exploited. Here’s why and how to secure them:
Risk of Exposure:
Best Practices:
Implementation: Secure Authentication in Node.js and Next.js
Here’s a step-by-step guide to implementing a secure token-based authentication system:
Backend: Node.js with Express
The backend is responsible for issuing, refreshing, and validating tokens.
Key Steps:
Backend Code:
app.post('/login', (req, res) => {
const { username } = req.body;
if (!username) return res.status(400).json({ message: 'Username is required' });
const user = { username };
const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);
// Store refresh token in HTTP-only cookie
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true, // Use true in production
sameSite: 'strict',
});
res.json({ accessToken });
});
Token Refresh Logic:
app.post('/refresh-token', (req, res) => {
const refreshToken = req.cookies.refreshToken;
if (!refreshToken) return res.status(403).json({ message: 'Invalid refresh token' });
jwt.verify(refreshToken, REFRESH_TOKEN_SECRET, (err, user) => {
if (err) return res.status(403).json({ message: 'Token expired or invalid' });
const newAccessToken = generateAccessToken(user);
const newRefreshToken = generateRefreshToken(user);
// Replace old refresh token
res.cookie('refreshToken', newRefreshToken, {
httpOnly: true,
secure: true,
sameSite: 'strict',
});
res.json({ accessToken: newAccessToken });
});
});
领英推荐
Frontend: Next.js
The frontend handles login, token storage, and token renewal.
Login Component:
const handleLogin = async () => {
try {
const response = await axios.post('/login', { username });
localStorage.setItem('accessToken', response.data.accessToken); // Temporarily store access token
router.push('/protected');
} catch (error) {
console.error('Login failed:', error.response.data.message);
}
};
Protected Routes with Token Refresh:
const fetchProtectedData = async () => {
try {
const response = await axios.get('/protected', {
headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` },
});
setData(response.data.message);
} catch (error) {
if (error.response.status === 403) {
// Attempt to refresh token
const refreshResponse = await axios.post('/refresh-token');
localStorage.setItem('accessToken', refreshResponse.data.accessToken);
fetchProtectedData(); // Retry request
} else {
console.error('Access denied:', error.response.data.message);
}
}
};
Key Security Features
HTTP-Only Cookies for Refresh Tokens:
Token Rotation:
Short-Lived Access Tokens:
Logout and Token Revocation:
Complete Authentication Workflow
Login:
Access Token Expiry:
Token Rotation:
Logout:
Conclusion
By following these practices, you can implement a secure, scalable authentication system using refresh tokens in Node.js and Next.js. The key takeaway is to minimize the exposure of sensitive tokens, leverage secure cookies, and ensure robust session management through token rotation and short lifespans.
Authentication is never one-size-fits-all, so adapt these principles based on your application’s needs and user base.
Software Architect & Tech SME @ Quantiphi | AI Enthusiast | SaaS Builder | Tech Strategist | GCP Expert
2 个月https://medium.com/@prashanth.ssa/building-a-secure-authentication-flow-using-refresh-tokens-in-node-js-and-next-js-8271fb29cc22