csrf-csrf
v4.0.3
Published
A utility package to help implement stateless CSRF protection using the Double Submit Cookie Pattern in express.
Downloads
316,166
Readme
npm install cookie-parser csrf-csrf// ESM
import { doubleCsrf } from "csrf-csrf";
// CommonJS
const { doubleCsrf } = require("csrf-csrf");const {
invalidCsrfTokenError, // This is just for convenience if you plan on making your own middleware.
generateCsrfToken, // Use this in your routes to provide a CSRF token.
validateRequest, // Also a convenience if you plan on making your own middleware.
doubleCsrfProtection, // This is the default CSRF protection middleware.
} = doubleCsrf({
getSecret = (req) => 'return some cryptographically pseudorandom secret here',
getSessionIdentifier = (req) => req.session.id // return the requests unique identifier
});const myRoute = (req, res) => {
const csrfToken = generateCsrfToken(req, res);
// You could also pass the token into the context of a HTML response.
res.json({ csrfToken });
};
const myProtectedRoute = (req, res) =>
res.json({ unpopularOpinion: "Game of Thrones was amazing" });request.csrfToken(); // same as generateCsrfToken(req, res);// Make sure your session middleware is registered before these
express.use(session);
express.use(cookieParser);
express.get("/csrf-token", myRoute);
express.use(doubleCsrfProtection);
// Any non GET routes registered after this will be considered "protected"app.get("/secret-stuff", doubleCsrfProtection, myProtectedRoute);(req, res, next) => {
getCsrfTokenAsync(req)
.then((token) => {
req.asyncCsrfToken = token;
next();
})
.catch((error) => next(error));
};(req) => req.asyncCsrfToken;When initialising doubleCsrf, you have a lot of options available for configuration, the only required options are getSecret and getSessionIdentifier, the rest have sensible defaults (shown below).
const doubleCsrfUtilities = doubleCsrf({
getSecret: () => "Secret", // A function that optionally takes the request and returns a secret
getSessionIdentifier: (req) => req.session.id, // A function that returns the unique identifier for the request
cookieName: "__Host-psifi.x-csrf-token", // The name of the cookie to be used, recommend using Host prefix.
cookieOptions: {
sameSite = "strict",
path = "/",
secure = true,
httpOnly = true,
...remainingCookieOptions // See cookieOptions below
},
size: 32, // The size of the random value used to construct the message used for hmac generation
ignoredMethods: ["GET", "HEAD", "OPTIONS"], // A list of request methods that will not be protected.
getCsrfTokenFromRequest: (req) => req.headers["x-csrf-token"], // A function that returns the token from the request
skipCsrfProtection: undefined
});(request?: Request) => string | string[](request: Request) => string;string;{
sameSite?: string;
path?: string;
secure?: boolean
...remainingCookieOptions // See below.
}{
sameSite: "strict",
path: "/",
secure: true,
httpOnly: true
} maxAge?: number | undefined;
expires?: Date | undefined;
domain?: string | undefined;
encode?: (val: string) => stringstring;string;(req: Request) => string | null | undefined;(req: Request) => req.headers["x-csrf-token"];string;Array<CsrfRequestMethod>;number;statusCode?: number;
message?: string;
code?: string | undefined;{
statusCode: 403,
message: "invalid csrf token",
code: "EBADCSRFTOKEN"
}Used to customise the error response statusCode, the contained error message, and its code, the error is constructed via createHttpError. The default values match that of csurf for convenience.
(req: Request) => boolean;(request: Request, response: Response, next: NextFunction) => void(
request: Request,
response: Response,
{
cookieOptions?: CookieOptions, // allows overriding of cookieOptions
overwrite?: boolean, // Set to true to force a new token to be generated
validateOnReuse?: boolean, // Deprecated, leave as default
} // optional
) => string;generateCsrfToken(req, res, { overwrite: true }); // This will force a new token to be generated, and a new cookie to be set, even if one already existsgenerateCsrfToken(req, res, { overwrite: true }); // As overwrite is true a new CSRF token will be generated.
generateCsrfToken(req, res, { overwrite: false }); // As overwrite is false, the existing CSRF token will be reused from the CSRF token cookie
generateCsrfToken(req, res); // same as previous
generateCsrfToken(req, res, { overwrite: false, validateOnReuse: true }); // DEPRECATED - As validateOnReuse is true, if the CSRF token from the cookie is invalid, an error will be thrownreq.csrfToken(); // same as generateCsrfToken(req, res);
req.csrfToken({ overwrite: true }); // same as generateCsrfToken(req, res, { overwrite: true });
req.csrfToken(req, res, { overwrite: false });(req: Request) => boolean;