This commit is contained in:
rgrgogu
2026-05-05 23:18:47 +08:00
parent 5aeb959e92
commit a8f10a25d7
38 changed files with 5992 additions and 2 deletions
+53
View File
@@ -0,0 +1,53 @@
/***********************************************************************************************************************************************************************
* File Name: csrf.middleware.js
* Type of Program: Middleware
* Description: CSRF protection using the `csurf` package (Double Submit Cookie pattern).
* - csrfProtection → the csurf middleware instance (attach to state-changing routes)
* - getCsrfToken → GET /csrf-token handler — sends the token to the client
* - csrfErrorHandler → catches EBADCSRFTOKEN and returns a 403
*
* NOTE: Because we use stateless JWT (no server sessions), CSRF is only
* relevant for cookie-based flows (e.g., CSRF token embedded in form headers).
* For REST / SPA clients, the standard practice is to omit CSRF and rely on
* the Authorization Bearer header (which is already CSRF-safe by design).
* This file keeps CSRF available for SSR / hybrid flows.
*
* Author: rgrgogu
* Date Created: Oct. 6, 2025
***********************************************************************************************************************************************************************
* HOW TO USE:
* // 1. Mount the token endpoint (public):
* app.get('/api/csrf-token', getCsrfToken);
*
* // 2. Apply to state-mutating cookie-based routes:
* router.post('/login', csrfProtection, loginHandler);
*
* // 3. Register the error handler AFTER all routes:
* app.use(csrfErrorHandler);
***********************************************************************************************************************************************************************/
const csurf = require('csurf');
const R = require('../utils/response.util');
/** csurf instance — stores token in a signed cookie */
const csrfProtection = csurf({ cookie: { httpOnly: true, sameSite: 'strict' } });
/**
* GET /api/csrf-token
* Returns the CSRF token the client must echo back on state-changing requests
* via the `X-CSRF-Token` header or `_csrf` body field.
*/
const getCsrfToken = (req, res) => {
res.json({ csrfToken: req.csrfToken() });
};
/**
* Error handler for invalid / missing CSRF tokens.
* Must be registered as Express error-handling middleware (4 args).
*/
const csrfErrorHandler = (err, req, res, next) => {
if (err.code === 'EBADCSRFTOKEN')
return R.error(res, 'Invalid or missing CSRF token.', 403);
next(err);
};
module.exports = { csrfProtection, getCsrfToken, csrfErrorHandler };