Authentication is a cornerstone of web application security. While basic authentication methods may suffice for simple applications, advanced authentication mechanisms are essential for building secure, scalable, and feature-rich systems. In this chapter, we will explore advanced authentication techniques like JSON Web Token (JWT) blacklisting and OAuth 2.0 flows in Express.js. Starting with the fundamentals, we will progress to advanced concepts, illustrating each with practical examples.
By the end of this chapter, you’ll have a comprehensive understanding of how to implement and manage advanced authentication mechanisms in your Express applications, ensuring robust security and scalability.
Authentication is the process of verifying the identity of a user or system. Common types include:
Basic techniques often fall short in scenarios involving:
JSON Web Tokens (JWT) are compact, self-contained tokens used for securely transmitting information between parties. A JWT consists of three parts:
npm install express jsonwebtoken body-parser
const express = require('express');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
const SECRET_KEY = "your_secret_key"; // Replace with a secure key
// Login Route: Generates JWT
app.post('/login', (req, res) => {
const { username, password } = req.body;
// In production, validate username and password from DB
if (username === 'user' && password === 'password') {
const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' });
res.json({ token });
} else {
res.status(401).json({ message: 'Invalid credentials' });
}
});
// Protected Route: Requires JWT
app.get('/protected', (req, res) => {
const token = req.headers['authorization'];
if (!token) return res.status(403).json({ message: 'Token missing' });
jwt.verify(token, SECRET_KEY, (err, decoded) => {
if (err) return res.status(401).json({ message: 'Invalid token' });
res.json({ message: 'Access granted', user: decoded });
});
});
app.listen(3000, () => console.log('Server running on http://localhost:3000'));
jwt.sign
.jwt.verify
and grants access if valid.JWT blacklisting is a technique to revoke tokens by maintaining a list of invalidated tokens.
One way to blacklist tokens is by storing their identifiers (e.g., JTI or token signature) in a database or cache.
npm install redis
const redis = require('redis');
const client = redis.createClient(); // Connect to Redis
// Middleware to check blacklisted tokens
const checkBlacklist = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) return res.status(403).json({ message: 'Token missing' });
jwt.verify(token, SECRET_KEY, (err, decoded) => {
if (err) return res.status(401).json({ message: 'Invalid token' });
client.get(decoded.jti, (err, data) => {
if (data) {
return res.status(401).json({ message: 'Token blacklisted' });
}
next();
});
});
};
// Logout Route: Blacklists a token
app.post('/logout', (req, res) => {
const token = req.headers['authorization'];
const { jti } = jwt.decode(token); // Decode to get token ID
client.set(jti, true, 'EX', 3600); // Blacklist token for 1 hour
res.json({ message: 'Token blacklisted' });
});
OAuth 2.0 is an authorization framework that enables third-party applications to obtain limited access to a resource on behalf of the user. It is commonly used for:
npm install express axios
const express = require('express');
const axios = require('axios');
const app = express();
const CLIENT_ID = 'your_google_client_id';
const CLIENT_SECRET = 'your_google_client_secret';
const REDIRECT_URI = 'http://localhost:3000/oauth-callback';
const AUTH_URL = `https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=email`;
app.get('/auth/google', (req, res) => {
res.redirect(AUTH_URL); // Redirect user to Google for authorization
});
app.get('/oauth-callback', async (req, res) => {
const { code } = req.query;
try {
const tokenResponse = await axios.post('https://oauth2.googleapis.com/token', {
code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
grant_type: 'authorization_code',
});
const { access_token } = tokenResponse.data;
const userResponse = await axios.get('https://www.googleapis.com/oauth2/v1/userinfo?alt=json', {
headers: { Authorization: `Bearer ${access_token}` },
});
res.json(userResponse.data);
} catch (error) {
res.status(500).json({ message: 'OAuth Error', error });
}
});
app.listen(3000, () => console.log('Server running on http://localhost:3000'));
Advanced authentication mechanisms like JWT and OAuth 2.0 provide powerful tools for securing modern web applications. Using JWT for stateless authentication. Revoking tokens by maintaining a blacklist. Enabling secure third-party integrations. These techniques enhance your application's security and scalability. By understanding and implementing them, you can ensure robust authentication tailored to your application's needs. Happy coding !❤️