Validate session cookies in Elysia
CSRF protection must be implemented when using cookies and forms. This can be easily done by comparing the Origin and Host header.
We recommend creating a middleware to validate requests and store the current user inside Context with App.derive(). You can get the cookie name with Lucia.sessionCookieName and validate the session cookie with Lucia.validateSession(). Make sure to delete the session cookie if it's invalid and create a new session cookie when the expiration gets extended, which is indicated by Session.fresh.
// src/middleware.ts
import { verifyRequestOrigin } from "lucia";
import type { User, Session } from "lucia";
const app = new Elysia().derive(
async (
context
): Promise<{
user: User | null;
session: Session | null;
}> => {
// CSRF check
if (context.request.method !== "GET") {
const originHeader = context.request.headers.get("Origin");
// NOTE: You may need to use `X-Forwarded-Host` instead
const hostHeader = context.request.headers.get("Host");
if (!originHeader || !hostHeader || !verifyRequestOrigin(originHeader, [hostHeader])) {
return {
user: null,
session: null
};
}
}
// use headers instead of Cookie API to prevent type coercion
const cookieHeader = context.request.headers.get("Cookie") ?? "";
const sessionId = lucia.readSessionCookie(cookieHeader);
if (!sessionId) {
return {
user: null,
session: null
};
}
const { session, user } = await lucia.validateSession(sessionId);
if (session && session.fresh) {
const sessionCookie = lucia.createSessionCookie(session.id);
context.cookie[sessionCookie.name].set({
value: sessionCookie.value,
...sessionCookie.attributes
});
}
if (!session) {
const sessionCookie = lucia.createBlankSessionCookie();
context.cookie[sessionCookie.name].set({
value: sessionCookie.value,
...sessionCookie.attributes
});
}
return {
user,
session
};
}
);
This will allow you to access the current user with Context.user.
app.get("/", async (context) => {
if (!context.user) {
return new Response(null, {
status: 401
});
}
// ...
});