I made middleware to send a CSRF token to a template and used it globally.
realestate\middleware\csrfToken.ts:
import { Request, Response } from "express";
function csrfToken(req: Request, res: Response, next: any) {
res.locals.csrfToken = req.csrfToken();
next();
}
export default csrfToken;
realestate\app.ts:
import csurf from "tiny-csrf";
import csrfToken from "./middleware/csrfToken";
app.use(cookieParser(process.env.COOKIE_SECRET!));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(join(__dirname, "public")));
app.use(
session({
secret: process.env.SESSION_SECRET!,
resave: true,
saveUninitialized: true
})
);
app.disable("x-powered-by");
// view engine setup
app.set("view engine", "ejs").set("views", join(__dirname, "views"));
app.use(moment);
// 1 Authentication & authorization
app.use(getAuth);
// 4 CSRF tokens
app.use(csurf(process.env.CSRF_SECRET!));
app.use(csrfToken);
// 7 Security headers
app.use(securityHeaders);
Because not only I use the CSRF token login, register and other forms, but in logout form in a layout too.
realestate\views\partials\header.ejs:
<body class="d-flex flex-column">
<!-- Navbar -->
<nav class="navbar navbar-expand-md bg-secondary sticky-top py-0 mx-0 mb-3">
<div class="container-fluid">
<!-- ... -->
<div class="collapse navbar-collapse" id="toggler">
<!-- ... -->
<ul class="navbar-nav">
<!-- 1 Authentication & authorization -->
<% if (auth) { %>
<li class="nav-item btn btn-secondary px-md-1 py-md-3">
<a class="nav-link fw-semibold text-light" href="/korisnici/<%= auth.id %>">Profil</a>
</li>
<li class="nav-item btn btn-secondary px-md-1 py-md-3">
<form action="/odjava" method="post">
<!-- 4 CSRF tokens -->
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<input class="nav-link fw-semibold text-light" type="submit" value="Odjava">
</form>
</li>
<% } else { %>
<!-- ... -->
<% } %>
</ul>
</div>
</div>
</nav>
<main class="flex-grow-1">
<div class="container">
http://localhost:3000/oglasi Response cookies:
<html><body>
<!--StartFragment-->
csrfToken |
-- | --
expires | "2026-01-26T14:11:08.000Z"
httpOnly | true
path | "/"
samesite | "Strict"
value | "s:959cbef0a8674522e21950723868a348:7859594351832cab4e9f715161af31c3c9c7bb91e1d942a288c64f2b043713d8c3ffc00fbe77574db58305712a0714ca.S9TlbBnPvvfeXtZpJ9rNZ20LwmvoG8MUSpmaVjzRFmQ"
<!--EndFragment-->
</body>
</html>
http://localhost:3000/oglasi Request cookies:
<html><body>
<!--StartFragment-->
connect.sid | "s:aS4KDjoQyl1Sm3tj9A31tbBqub8HWOVj.kDOqaMRrSEi/XLVZKLTx5eTYUI0Fxyx6wtTpA0MoHUM"
-- | --
csrfToken | "s:0c58a4f3cce0f99a3d8264c02c851abd:6981b2d4d637ec8921681b2fbad221ae02d7b5d8cbb73171e1fc5db1da4c540d9252d2a6cc336c2f5967526c9fbc48d9.dajMYcbNKjPbk9sirKbRCl93K4mnQ4ytnqmCoknxaVQ"
jwt | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiaWF0IjoxNzY5NDM1MjQ1LCJleHAiOjE3Njk1MjE2NDV9.Wqce2DDH0FGmgaakDhB3ELKnU00aKdqoz3EqHdm2hFQ"
<!--EndFragment-->
</body>
</html>
But whenever I click the logout button, save button in listing card or post form data, the CSRF token is invalid.
realestate\views\partials\listings\list\card.ejs:
<!-- Card -->
<div class="card mb-3">
<!-- ... -->
<%- include("./footer", { authId }) %>
</div>
realestate\views\partials\listings\list\footer.ejs:
<!-- Card footer -->
<div class="card-footer d-flex justify-content-between align-items-center">
<!-- ... -->
<form action="/oglasi/cuvanje/<%= listing.id %>" method="post">
<!-- 4 CSRF tokens -->
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button class="btn btn-link" type="submit">
<% if (listing.isSaved(authId)) { %>
<i class="bi bi-bookmark-fill text-success fs-4"></i>
<% } else { %>
<i class="bi bi-bookmark text-success fs-4"></i>
<% } %>
</button>
</form>
</div>
Error:
Error: Did not get a valid CSRF token for 'POST /oglasi/cuvanje/2': 1223a98e-7613-4d3f-9f07-22594f6b4a7a v. undefined
http://localhost:3000/oglasi/cuvanje/2 Request cookies:
<html><body>
<!--StartFragment-->
|
-- | --
connect.sid | "s:aS4KDjoQyl1Sm3tj9A31tbBqub8HWOVj.kDOqaMRrSEi/XLVZKLTx5eTYUI0Fxyx6wtTpA0MoHUM"
jwt | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwiaWF0IjoxNzY5NDM1MjQ1LCJleHAiOjE3Njk1MjE2NDV9.Wqce2DDH0FGmgaakDhB3ELKnU00aKdqoz3EqHdm2hFQ"
<!--EndFragment-->
</body>
</html>
I made middleware to send a CSRF token to a template and used it globally.
realestate\middleware\csrfToken.ts:
realestate\app.ts:
Because not only I use the CSRF token login, register and other forms, but in logout form in a layout too.
realestate\views\partials\header.ejs:
http://localhost:3000/oglasiResponse cookies:http://localhost:3000/oglasiRequest cookies:But whenever I click the logout button, save button in listing card or post form data, the CSRF token is invalid.
realestate\views\partials\listings\list\card.ejs:
realestate\views\partials\listings\list\footer.ejs:
Error:
http://localhost:3000/oglasi/cuvanje/2Request cookies: