Authentication
Guide on implementing basic Token-based Authentication in ExpressJS, covering Auth Workflow, example workflow, and creating authenticated endpoints using a custom generateToken approach.
Authentication in ExpressJS
Authentication is the process of verifying the identity of a user or system interacting with your application. In ExpressJS, you can implement authentication by generating a simple token, storing it, and verifying it on protected endpoints.
This guide focuses on a simple custom token approach using generateToken.
Auth Workflow Overview
A typical authentication flow consists of the following steps:
- User Login – The user submits credentials (username and password).
- Token Generation – On successful validation, the server generates a random token.
- Token Storage – The token is stored server-side (e.g., in memory).
- Authenticated Requests – The client sends the token in headers with each request.
- Token Verification – Middleware verifies the token’s validity.
- Logout (Optional) – The token is removed from storage.
Example Auth Workflow
Step 1: User Submits Credentials
app.post('/login', (req, res) => {
const { username, password } = req.body;
// Example hardcoded user for demonstration
const validUser = { username: 'admin', password: 'password123' };
if (username === validUser.username && password === validUser.password) {
const token = generateToken();
tokens[token] = username; // Store token mapping
res.json({ token, message: 'Login successful' });
} else {
res.status(401).json({ message: 'Invalid credentials' });
}
});Step 2: Token Generation Function
const crypto = require('crypto');
function generateToken() {
return crypto.randomBytes(32).toString('hex');
}
const tokens = {}; // Simple in-memory storage for tokensWhy Send the Token in the Header Instead of the Request Body?
The token should be sent in the Authorization header because:
- Standard Practice: The HTTP standard defines the Authorization header for authentication purposes.
- Statelessness: Tokens in headers help maintain a stateless API where each request is independent.
- Security: Sending tokens in the body is error-prone, especially in GET requests where bodies are typically ignored or unsupported. Headers ensure the token is consistently present in every request.
- Caching Issues: Some caching proxies or CDNs may cache requests based on the body content, which is not ideal for authentication.
- Separation of Concerns: Headers are intended for metadata like authorization, whereas the body should carry only the resource data.
Creating Authenticated Endpoints
Use middleware to protect sensitive routes by validating the token.
Authentication Middleware
function authenticateToken(req, res, next) {
const token = req.headers['authorization'];
if (token && tokens[token]) {
req.user = tokens[token]; // Attach user info to request
next();
} else {
res.status(403).json({ message: 'Access denied. Invalid token.' });
}
}Protected Route Example
app.get('/profile', authenticateToken, (req, res) => {
res.json({ message: `Hello, ${req.user}. This is your profile.` });
});Logout Workflow (Optional)
app.post('/logout', authenticateToken, (req, res) => {
const token = req.headers['authorization'];
delete tokens[token];
res.json({ message: 'Logged out successfully.' });
});Important Notes
- Token storage here is in-memory, which is not durable across server restarts. Use persistent storage like a database or Redis for production.
- HTTPS is mandatory in production to prevent token interception.
- Implement token expiration logic manually if needed.
CORS
In-depth guide to understanding, configuring, and handling CORS in web applications and ExpressJS servers.
JWTs
In-depth guide on implementing JWT-based authentication in ExpressJS, including token vs JWT comparison, JWT creation, verification, secure practices, middleware handling, and a full example site structure.