csrf-csrf
v3.0.8
Published
A utility package to help implement stateless CSRF protection using the Double Submit Cookie Pattern in express.
Downloads
142,158
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.
generateToken, // Use this in your routes to provide a CSRF hash + token cookie and token.
validateRequest, // Also a convenience if you plan on making your own middleware.
doubleCsrfProtection, // This is the default CSRF protection middleware.
} = doubleCsrf(doubleCsrfOptions);
const myRoute = (req, res) => {
const csrfToken = generateToken(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 generateToken(req, res);
// Make sure your session middleware is registered before these
express.use(session);
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 creating your doubleCsrf, you have a few options available for configuration, the only required option is getSecret, 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) => "", // A function that should return the session identifier for a given request
cookieName: "__Host-psifi.x-csrf-token", // The name of the cookie to be used, recommend using Host prefix.
cookieOptions: {
sameSite = "lax", // Recommend you make this strict if posible
path = "/",
secure = true,
...remainingCookieOptions // See cookieOptions below
},
size: 64, // The size of the generated tokens in bits
ignoredMethods: ["GET", "HEAD", "OPTIONS"], // A list of request methods that will not be protected.
getTokenFromRequest: (req) => req.headers["x-csrf-token"], // A function that returns the token from the request
});
(request?: Request) => string | string[]
(req: Request) => string;
(req: Request) => req.session.id;
string;
{
sameSite?: string;
path?: string;
secure?: boolean
...remainingCookieOptions // See below.
}
{
sameSite: "lax",
path: "/",
secure: true
}
maxAge?: number | undefined;
signed?: boolean | undefined;
expires?: Date | undefined;
domain?: string | undefined;
encode?: (val: string) => string
(req: Request) => string | null | undefined;
(req: Request) => req.headers["x-csrf-token"];
Array<RequestMethod>;
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 it's code, the error is constructed via createHttpError. The default values match that of csurf for convenience.
(request: Request, response: Response, next: NextFunction) => void
(
request: Request,
response: Response,
overwrite?: boolean, // Set to true to force a new token to be generated
validateOnReuse?: boolean, // Set to false to generate a new token if token re-use is invalid
) => string;
generateToken(req, res, true); // This will force a new token to be generated, and a new cookie to be set, even if one already exists
generateToken(req, res, true); // As overwrite is true, an error will never be thrown.
generateToken(req, res, false); // As validateOnReuse is true (default), an error will be thrown if the cookie is invalid.
generateToken(req, res, false, false); // As validateOnReuse is false, an error will never be thrown, even if the cookie is invalid. Instead, a new cookie will be generated if it is found to be invalid.
req.csrfToken(); // same as generateToken(req, res) and generateToken(req, res, false);
req.csrfToken(true); // same as generateToken(req, res, true);
req.csrfToken(false, false); // same as generateToken(req, res, false, false);
(req: Request) => boolean;