Implementing JWT authentication in Node.js typically uses the jsonwebtoken library. Here are the complete implementation steps:
1. Install Dependencies
bashnpm install jsonwebtoken npm install @types/jsonwebtoken --save-dev # TypeScript
2. Generate JWT Token
javascriptconst jwt = require('jsonwebtoken'); const SECRET_KEY = 'your-secret-key'; // Should read from environment variables in production function generateToken(payload, expiresIn = '1h') { return jwt.sign(payload, SECRET_KEY, { expiresIn, issuer: 'your-app.com', audience: 'your-api' }); } // Usage example const user = { id: '123', username: 'john', role: 'admin' }; const token = generateToken(user, '2h'); console.log(token);
3. Verify JWT Token
javascriptfunction verifyToken(token) { try { const decoded = jwt.verify(token, SECRET_KEY, { issuer: 'your-app.com', audience: 'your-api' }); return { success: true, decoded }; } catch (error) { if (error.name === 'TokenExpiredError') { return { success: false, error: 'Token expired' }; } else if (error.name === 'JsonWebTokenError') { return { success: false, error: 'Invalid token' }; } return { success: false, error: error.message }; } } // Usage example const result = verifyToken(token); if (result.success) { console.log('Decoded:', result.decoded); } else { console.log('Error:', result.error); }
4. Express Middleware Implementation
javascriptconst express = require('express'); const app = express(); // Authentication middleware function authMiddleware(req, res, next) { const authHeader = req.headers['authorization']; if (!authHeader) { return res.status(401).json({ error: 'No token provided' }); } const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : authHeader; const result = verifyToken(token); if (!result.success) { return res.status(401).json({ error: result.error }); } req.user = result.decoded; next(); } // Login route - generate token app.post('/login', (req, res) => { const { username, password } = req.body; // Verify user credentials (query database in real projects) if (username === 'admin' && password === 'password') { const token = generateToken({ id: '123', username, role: 'admin' }, '2h'); res.json({ success: true, token, expiresIn: '2h' }); } else { res.status(401).json({ error: 'Invalid credentials' }); } }); // Protected route app.get('/profile', authMiddleware, (req, res) => { res.json({ user: req.user, message: 'This is protected data' }); }); app.listen(3000, () => { console.log('Server running on port 3000'); });
5. Refresh Token Implementation
javascriptconst crypto = require('crypto'); // Store refresh tokens (use Redis in production) const refreshTokens = new Map(); function generateRefreshToken() { return crypto.randomBytes(40).toString('hex'); } // Generate access token and refresh token on login app.post('/login', (req, res) => { const { username, password } = req.body; if (username === 'admin' && password === 'password') { const accessToken = generateToken({ id: '123', username }, '15m'); // Short-term const refreshToken = generateRefreshToken(); refreshTokens.set(refreshToken, '123'); res.json({ accessToken, refreshToken, expiresIn: '15m' }); } else { res.status(401).json({ error: 'Invalid credentials' }); } }); // Refresh token app.post('/refresh', (req, res) => { const { refreshToken } = req.body; if (!refreshToken || !refreshTokens.has(refreshToken)) { return res.status(401).json({ error: 'Invalid refresh token' }); } const userId = refreshTokens.get(refreshToken); const accessToken = generateToken({ id: userId }, '15m'); res.json({ accessToken, expiresIn: '15m' }); }); // Logout - delete refresh token app.post('/logout', (req, res) => { const { refreshToken } = req.body; refreshTokens.delete(refreshToken); res.json({ success: true }); });
6. TypeScript Version
typescriptimport jwt from 'jsonwebtoken'; interface TokenPayload { id: string; username: string; role?: string; } interface DecodedToken extends TokenPayload { iss: string; aud: string; iat: number; exp: number; } const SECRET_KEY = process.env.JWT_SECRET || 'your-secret-key'; export function generateToken( payload: TokenPayload, expiresIn: string | number = '1h' ): string { return jwt.sign(payload, SECRET_KEY, { expiresIn, issuer: 'your-app.com', audience: 'your-api' }); } export function verifyToken(token: string): { success: boolean; decoded?: DecodedToken; error?: string; } { try { const decoded = jwt.verify(token, SECRET_KEY) as DecodedToken; return { success: true, decoded }; } catch (error: any) { if (error.name === 'TokenExpiredError') { return { success: false, error: 'Token expired' }; } return { success: false, error: 'Invalid token' }; } }
7. Environment Variable Configuration
bash# .env JWT_SECRET=your-super-secret-key-change-in-production JWT_EXPIRES_IN=1h JWT_REFRESH_EXPIRES_IN=7d
Best Practices
- Use strong keys (at least 32 characters)
- Read keys from environment variables
- Set reasonable expiration times
- Implement Refresh Token mechanism
- Use HTTPS for transmission
- Verify issuer and audience
- Catch and handle all errors
- Log authentication failures
With these implementations, you can securely use JWT for authentication in your Node.js applications.