How to Implement JWT Authentication: A Step-by-Step Guide
JSON Web Tokens (JWT) offer a stateless, secure way to authenticate users in web applications. Unlike session-based auth, JWTs store user claims directly in the token, making them ideal for distributed systems and RESTful APIs.
A JWT consists of three parts: a base64-encoded header containing the signing algorithm, a payload with user claims like “id” or “role”, and a signature created by hashing the header and payload with a secret key. The signature guarantees token integrity.
1. Generate Tokens on Login
When a user authenticates, create a signed token. In Node.js, use the jsonwebtoken package:
- Install:
npm install jsonwebtoken - Sign:
jwt.sign({ id: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '1h' }) - Return the token to the client in the response body.
2. Protect Routes with Middleware
Create a middleware function that verifies the token on protected endpoints:
- Extract the token from the Authorization header (Bearer token).
- Verify using
jwt.verify(token, JWT_SECRET). - Attach the decoded payload to
req.userfor use in route handlers. - Return 401 if the token is missing or invalid.
3. Handle Token Expiry and Refresh
Access tokens should be short-lived (15-60 minutes). Implement refresh tokens to improve security and user experience:
- Store a refresh token server-side or in an HTTP-only cookie.
- Add a
/refreshendpoint that issues a new access token when the old one expires. - Rotate refresh tokens on each request to reduce replay risk.
4. Client-Side Integration
On the frontend, store the access token in memory, not localStorage, to avoid XSS attacks. Attach it to requests:
- Set the Authorization header:
Bearer <token>. - Redirect to the login page when the server returns 401.
Conclusion
JWT authentication is straightforward to implement and scales well across microservices. Secure your secret key, use HTTPS, keep tokens short-lived, and always validate the signature to prevent tampering.