Session cookies
This page builds upon the API defined in the Basic session API page.
Framework and library specific guides are also available:
CSRF protection
CSRF protection is a must when using cookies. A very simple way to prevent CSRF attacks is to check the Origin
header for non-GET requests. If you rely on this method, it is crucial that your application does not use GET requests for modifying resources.
// `HTTPRequest` and `HTTPResponse` are generic interfaces.
// Adjust this code to fit your framework's API.
function handleRequest(request: HTTPRequest, response: HTTPResponse): void {
if (request.method !== "GET") {
const origin = request.headers.get("Origin");
// You can also compare it against the Host or X-Forwarded-Host header.
if (origin === null || origin !== "https://example.com") {
response.setStatusCode(403);
return;
}
}
// ...
}
Cookies
If the frontend and backend are hosted on the same domain, session cookies should have the following attributes:
HttpOnly
: Cookies are only accessible server-sideSameSite=Lax
: UseStrict
for critical websitesSecure
: Cookies can only be sent over HTTPS (Should be omitted when testing on localhost)Max-Age
orExpires
: Must be defined to persist cookiesPath=/
: Cookies can be accessed from all routes
Lucia v3 used
auth_session
as the session cookie name.
// `HTTPResponse` is a generic interface.
// Adjust this code to fit your framework's API.
export function setSessionTokenCookie(response: HTTPResponse, token: string, expiresAt): void {
if (env === Env.PROD) {
// When deployed over HTTPS
response.headers.add(
"Set-Cookie",
`session=${token}; HttpOnly; SameSite=Lax; Expires=${expiresAt.toUTCString()}; Path=/; Secure;`
);
} else {
// When deployed over HTTP (localhost)
response.headers.add(
"Set-Cookie",
`session=${token}; HttpOnly; SameSite=Lax; Expires=${expiresAt.toUTCString()}; Path=/`
);
}
}
export function deleteSessionTokenCookie(response: HTTPResponse): void {
if (env === Env.PROD) {
// When deployed over HTTPS
response.headers.add(
"Set-Cookie",
"session=; HttpOnly; SameSite=Lax; Max-Age=0; Path=/; Secure;"
);
} else {
// When deployed over HTTP (localhost)
response.headers.add("Set-Cookie", "session=; HttpOnly; SameSite=Lax; Max-Age=0; Path=/");
}
}
Session validation
Sessions can be validated by getting the cookie and using the validateSession()
function we created. If the session is invalid, delete the session cookie. Importantly, we recommend setting a new session cookie after validation to persist the cookie for an extended time.
import {
validateSessionToken,
deleteSessionTokenCookie,
setSessionTokenCookie
} from "./session.js";
// `HTTPRequest` and `HTTPResponse` are generic interfaces.
// Adjust this code to fit your framework's API.
function handleRequest(request: HTTPRequest, response: HTTPResponse): void {
// csrf protection
if (request.method !== "GET") {
const origin = request.headers.get("Origin");
// You can also compare it against the Host or X-Forwarded-Host header.
if (origin === null || origin !== "https://example.com") {
response.setStatusCode(403);
return;
}
}
// session validation
const cookies = parseCookieHeader(request.headers.get("Cookie") ?? "");
const token = cookies.get("session");
if (token === null) {
response.setStatusCode(401);
return;
}
const { session, user } = await validateSessionToken(token);
if (session === null) {
deleteSessionTokenCookie(response);
response.setStatusCode(401);
return;
}
setSessionTokenCookie(response, token, session, expiresAt);
// ...
}