underrate's picture
Initial commit
d53e5b4 verified
Raw
History Blame Contribute Delete
1.48 kB
import { Request, Response, NextFunction } from 'express';
import crypto from 'crypto';
/**
* Middleware to generate a CSRF token for the session / request.
* If the request doesn't have a token cookie, one is generated and attached.
*/
export const csrfProtection = (req: Request, res: Response, next: NextFunction) => {
// Determine the token
let token = req.cookies['csrf-token'];
if (!token) {
token = crypto.randomBytes(32).toString('hex');
res.cookie('csrf-token', token, {
httpOnly: false, // Must be readable by frontend JS to set header
sameSite: 'lax',
secure: process.env.NODE_ENV === 'production',
path: '/',
});
}
// Attach to request object for use in endpoints if needed
(req as any).csrfToken = token;
// Fast-path for GET / OPTIONS / HEAD
if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
return next();
}
// For POST/PATCH/DELETE require the token in the headers
const clientToken = req.headers['x-csrf-token'];
if (!clientToken || clientToken !== token) {
return res.status(403).json({
error: 'CSRF token missing or invalid',
});
}
next();
};
/**
* Endpoint to explicitly fetch the CSRF token
*/
export const getCsrfToken = (req: Request, res: Response) => {
res.status(200).json({ csrfToken: (req as any).csrfToken });
};