Express and JWT: Implementing Token-Based Authentication
Token-based authentication is a popular method for securing web applications, offering a stateless, scalable approach to user authentication. JSON Web Tokens (JWT) are a key component in this process, enabling secure transmission of data between parties as a JSON object. This article explores how to implement JWT-based authentication in Express, a widely-used Node.js framework.
Setting Up Express and JWT
To get started with token-based authentication in Express, you’ll need to set up a basic Express application and install the necessary packages, including `jsonwebtoken` for creating and verifying JWTs.
Example: Setting Up an Express Application
```javascript const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); app.use(express.json()); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); }); ```
Creating a JWT Token
The first step in token-based authentication is to generate a token when a user successfully logs in. This token is then sent back to the client, which can use it for subsequent requests.
Example: Generating a JWT Token upon User Login
```javascript app.post('/login', (req, res) => { const { username, password } = req.body; // For demonstration purposes, we'll assume these credentials are valid const user = { id: 1, username }; // Generate a JWT token const token = jwt.sign({ user }, 'your_jwt_secret_key', { expiresIn: '1h' }); res.json({ token }); }); ```
Protecting Routes with JWT Middleware
Once a token is generated and sent to the client, it must be included in the Authorization header for subsequent requests to protected routes. The server can then verify the token and grant or deny access.
Example: Creating Middleware to Verify JWT Tokens
```javascript const authenticateJWT = (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (token) { jwt.verify(token, 'your_jwt_secret_key', (err, user) => { if (err) { return res.sendStatus(403); } req.user = user; next(); }); } else { res.sendStatus(401); } }; app.get('/protected', authenticateJWT, (req, res) => { res.send('This is a protected route'); }); ```
Refreshing JWT Tokens
Since JWT tokens typically have an expiration time, it’s important to handle token renewal to ensure a smooth user experience. This can be done by issuing a new token before the current one expires.
Example: Refreshing an Expired Token
```javascript app.post('/token', (req, res) => { const { token } = req.body; if (!token) { return res.sendStatus(401); } jwt.verify(token, 'your_jwt_secret_key', (err, user) => { if (err) { return res.sendStatus(403); } const newToken = jwt.sign({ user: user.user }, 'your_jwt_secret_key', { expiresIn: '1h' }); res.json({ token: newToken }); }); }); ```
Revoking Tokens
In some cases, you might need to revoke a user’s token, such as when they log out or their account is compromised. While JWT itself is stateless, you can implement token revocation by maintaining a blacklist of invalidated tokens.
Example: Implementing a Simple Token Revocation Mechanism
```javascript const blacklistedTokens = []; app.post('/logout', authenticateJWT, (req, res) => { const token = req.headers.authorization.split(' ')[1]; blacklistedTokens.push(token); res.send('Logged out'); }); app.use((req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (blacklistedTokens.includes(token)) { return res.sendStatus(401); } next(); }); ```
Conclusion
Implementing JWT-based authentication in an Express application provides a secure, scalable, and stateless way to handle user authentication. By generating tokens upon login, protecting routes with middleware, handling token renewal, and managing token revocation, you can create a robust authentication system for your web applications.
Further Reading:
Table of Contents