Page Middleware

Protect pages and handle authentication with middleware

Overview

Page middleware protects routes and handles authentication. Use middleware.ts files in your app directory.

Creating Middleware

Create a middleware.ts file to protect routes:

// app/middleware.ts import { redirect, getCookie } from "@axi-js/core"; import type { MiddlewareContext } from "@axi-js/core"; export async function middleware({ request }: MiddlewareContext) { const authToken = getCookie(request, "auth_token"); if (!authToken) { return redirect("/auth/login"); } // Add user to context return { user: { id: "123", role: "user" }, }; }

This protects all routes. Unauthenticated users are redirected to /auth/login.

Accessing Context

Middleware data flows to loaders and pages:

import type { LoaderContext, PageProps } from "@axi-js/core"; export async function loader({ context }: LoaderContext) { // Access middleware data return { user: context.user, }; } export default function Page({ data }: PageProps) { const { user } = data as { user: User }; return <h1>Welcome, {user.name}</h1>; }

Public Routes

Override parent middleware for public routes:

// app/auth/middleware.ts export async function middleware() { // Return empty object to allow access return {}; }

This makes all /auth routes public, overriding the root middleware.

Role-Based Access

Restrict routes by role:

// app/admin/middleware.ts import { redirect } from "@axi-js/core"; import type { MiddlewareContext } from "@axi-js/core"; export async function middleware({ context }: MiddlewareContext) { const user = context.user as { role: string }; if (user.role !== "admin") { return redirect("/dashboard"); } return { user }; }

Only admin users can access /admin routes.

Cascading Middleware

Middleware executes from child to parent:

  1. app/admin/middleware.ts (runs first)
  2. app/middleware.ts (runs if child returns undefined)

This allows specific routes to override general protection.

Built-in helpers for auth:

import { getCookie, setCookie, deleteCookie, redirect } from "@axi-js/core"; import type { MiddlewareContext } from "@axi-js/core"; export async function middleware({ request }: MiddlewareContext) { // Get cookie const token = getCookie(request, "auth_token"); // Set cookie const response = redirect("/dashboard"); setCookie(response, "session_id", "abc123", { httpOnly: true, secure: true, maxAge: 3600, }); return response; }

Complete Example

Authentication flow:

// app/middleware.ts - Protect all routes import { redirect, getCookie } from "@axi-js/core"; import type { MiddlewareContext } from "@axi-js/core"; export async function middleware({ request }: MiddlewareContext) { const token = getCookie(request, "auth_token"); if (!token) { return redirect("/auth/login"); } const user = await validateToken(token); return { user }; }
// app/auth/middleware.ts - Allow public access export async function middleware() { return {}; }
// app/admin/middleware.ts - Require admin import { redirect } from "@axi-js/core"; import type { MiddlewareContext } from "@axi-js/core"; export async function middleware({ context }: MiddlewareContext) { if (context.user?.role !== "admin") { return redirect("/dashboard"); } }