Handle requests

Reading and parsing request headers, validating sessions, and setting appropriate response headers for every protected endpoint is a bit tedious. To address this issue, Lucia provides Auth.handleRequest() which creates a new AuthRequest instance. This provides a few methods that make working with session cookies and bearer tokens easier. Refer to Using cookies and Using bearer tokens page on more about those methods.

const authRequest = auth.handleRequest();

const session = authRequest.validate();
authRequest.setSession(session);

const session = authRequest.validateBearerToken();

However, every framework and runtime has their own representation of an incoming request and outgoing response, such as the web standard Request/Response and Node.js’ IncomingMessage/OutgoingMessage. Lucia uses its own implementation of RequestContext as well, which is the default parameter type of Auth.handleRequest(). Since this is an annoying problem that is easy to solve, Lucia provides middleware.

Middleware allows you to pass framework and runtime specific request objects to Auth.handleRequest. While we provide a number of them, it’s easy to create and if you do, consider contributing to the project!

import { node } from "lucia/middleware";

lucia({
	// ...
	middleware: web() // pass Web middleware
});

// `Auth.handleRequest()` now accepts `Request`
const authRequest = auth.handleRequest(new Request());

List of middleware#

Lucia (default)#

The default middleware is the Lucia middleware. Auth.handleRequest() accepts RequestContext.

import { lucia } from "lucia/middleware";

Astro#

import { astro } from "lucia/middleware";
---
// .astro component
const authRequest = auth.handleRequest(Astro);
---
// API routes and middleware
export const get = async (context) => {
	const authRequest = auth.handleRequest(context);
	// ...
};

We recommend storing AuthRequest in locals.

Elysia#

import { elysia } from "lucia/middleware";
new Elysia().get("/", async (context) => {
	const authRequest = auth.handleRequest(context);
});

Express#

import { express } from "lucia/middleware";
app.get("/", (req, res) => {
	const authRequest = auth.handleRequest(req, res);
});

Fastify#

import { fastify } from "lucia/middleware";
server.get("/"(request, reply) => {
	const authRequest = auth.handleRequest(request, reply);
});

H3#

import { h3 } from "lucia/middleware";

Nuxt#

// api routes (server/api/index.ts)
export default defineEventHandler(async (event) => {
	const authRequest = auth.handleRequest(event);
	// ...
});

Hono#

import { hono } from "lucia/middleware";
app.get("/", async (context) => {
	const authRequest = auth.handleRequest(context);
});

Next.js#

nextjs_future() will replace nextjs() in the next next major release. While nextjs() isn’t deprecated, we recommend considering it as a legacy API.

import { nextjs_future } from "lucia/middleware";

Pages router#

// pages/index.tsx
export const getServerSideProps = async (context) => {
	const authRequest = auth.handleRequest(context);
};
// pages/index.ts
export default async (req: IncomingMessage, res: OutgoingMessage) => {
	const authRequest = auth.handleRequest({ req, res });
};
// pages/index.ts (deployed to edge)
export default async (request: NextRequest) => {
	// `AuthRequest.setSession()` is not supported when only `Request` is passed
	auth.handleRequest(request);
	// ...
	const session = await auth.createSession({
		// ...
	});
	const sessionCookie = auth.createSessionCookie(session);
	const response = new Response(null);
	response.headers.append("Set-Cookie", sessionCookie.serialize());
};

App router#

We recommend setting sessionCookie.expires configuration to false when using this middleware.

// app/page.tsx
import * as context from "next/headers";

export default () => {
	const authRequest = auth.handleRequest("GET", context);

	const experimentalFormActions = async () => {
		const authRequest = auth.handleRequest("POST", context);
	};
	// ...
};
// app/routes.ts
import * as context from "next/headers";

export const POST = async (request: NextRequest) => {
	const authRequest = auth.handleRequest(request.method, context);
	// ...
};

Middleware#

// middleware.ts
export const middleware = async (request: NextRequest) => {
	// `AuthRequest.setSession()` is not supported when only `NextRequest` is passed
	const authRequest = auth.handleRequest(request);
	// ...
	const session = await auth.createSession({
		// ...
	});
	const sessionCookie = auth.createSessionCookie(session);
	const response = new Response(null);
	response.headers.append("Set-Cookie", sessionCookie.serialize());
};

Node.js#

import { node } from "lucia/middleware";
const authRequest = auth.handleRequest(incomingMessage, outgoingMessage);

Qwik#

import { qwik } from "lucia/middleware";
const authRequest = auth.handleRequest(requestEvent as RequestEventLoader);
const authRequest = auth.handleRequest(requestEvent as RequestEventAction);

SvelteKit#

import { sveltekit } from "lucia/middleware";
// +page.server.ts
export const load = async (event) => {
	const authRequest = auth.handleRequest(event);
	// ...
};

export const actions = {
	default: async (event) => {
		const authRequest = auth.handleRequest(event);
		// ...
	}
};
// hooks.server.ts
export const handle = async ({ event, resolve }) => {
	event.locals.auth = auth.handleRequest(event);
	// ...
};

Web standard#

AuthRequest.setSession() is disabled when using the web() middleware. We recommend setting sessionCookie.expires configuration to false when using this middleware.

import { web } from "lucia/middleware";

const authRequest = auth.handleRequest(request as Request);
const authRequest = auth.handleRequest(request);
await authRequest.validate();
await authRequest.setSession(session); // error!

Remix#

export const loader = async ({ request }: LoaderArgs) => {
	const authRequest = auth.handleRequest(request);
	return json({});
};