patternjavascriptastroModerate
Astro middleware for authentication and request processing
Viewed 0 times
Astro 2.6+ (middleware stable)
astro middlewaredefineMiddlewarelocalsauthenticationsequencerequest interceptor
Problem
Running authentication checks or preprocessing logic on every request in Astro without a central place to handle it. Duplicating auth logic in every page.
Solution
Create src/middleware.ts to intercept all requests:
// src/middleware.ts
import { defineMiddleware, sequence } from 'astro:middleware';
const auth = defineMiddleware(async (context, next) => {
const session = context.cookies.get('session')?.value;
if (session) {
const user = await validateSession(session);
context.locals.user = user; // available in all pages
} else {
context.locals.user = null;
}
// Protect /admin routes
if (context.url.pathname.startsWith('/admin')) {
if (!context.locals.user) {
return context.redirect('/login');
}
}
return next();
});
const logging = defineMiddleware(async (context, next) => {
const start = Date.now();
const response = await next();
console.log(
return response;
});
export const onRequest = sequence(auth, logging);
// src/env.d.ts — type locals
declare namespace App {
interface Locals {
user: User | null;
}
}
// src/middleware.ts
import { defineMiddleware, sequence } from 'astro:middleware';
const auth = defineMiddleware(async (context, next) => {
const session = context.cookies.get('session')?.value;
if (session) {
const user = await validateSession(session);
context.locals.user = user; // available in all pages
} else {
context.locals.user = null;
}
// Protect /admin routes
if (context.url.pathname.startsWith('/admin')) {
if (!context.locals.user) {
return context.redirect('/login');
}
}
return next();
});
const logging = defineMiddleware(async (context, next) => {
const start = Date.now();
const response = await next();
console.log(
${context.request.method} ${context.url.pathname} ${Date.now() - start}ms);return response;
});
export const onRequest = sequence(auth, logging);
// src/env.d.ts — type locals
declare namespace App {
interface Locals {
user: User | null;
}
}
Why
Astro middleware runs before every page render and API endpoint. context.locals carries per-request data to pages and endpoints. sequence() composes middleware functions in order, similar to Express middleware chains.
Gotchas
- Middleware only runs in SSR mode (output: server or hybrid) — not for purely static pages
- Always call next() unless explicitly short-circuiting with a redirect
- context.locals is not available in client-side JavaScript — server-only
- Middleware runs for ALL requests including static assets unless filtered by URL
Code Snippets
Accessing middleware locals in Astro page
// Access locals in an Astro page
---
const { user } = Astro.locals;
if (!user) return Astro.redirect('/login');
---
<h1>Welcome {user.name}</h1>Context
When adding authentication or request preprocessing to an Astro SSR application
Revisions (0)
No revisions yet.