Skip to content

Next.js middleware for LMS auth & tenancy

Problem

No middleware.ts exists in either app. The LMS resolves tenants in Auth.js callbacks and checks auth in individual route handlers. Consequences:

  1. Cost: Unauthenticated requests to protected routes still invoke the Node.js runtime (billed per invocation on Vercel)
  2. Duplication: Tenant resolution logic repeated in auth callbacks and RBAC middleware
  3. UX: No centralized redirect for expired sessions — each page errors independently

Proposal

Add apps/lms/middleware.ts with:

  1. Auth check: Redirect to /learn/sign-in for protected routes when no session token cookie exists
  2. Tenant header injection: Resolve tenant slug from hostname once, pass as x-tenant-slug header to downstream
  3. Static asset bypass: Matcher excludes /_next/*, /api/auth/*, /api/health, /favicon/*

Important constraints:

  • Middleware runs on Vercel Edge — cannot do DB lookups
  • RBAC stays in route handlers (requires DB for permission checks)
  • Auth.js session validation remains in callbacks (middleware only checks cookie presence)

Acceptance criteria

  • middleware.ts created with config.matcher excluding static paths
  • Unauthenticated requests to /learn/* and /admin/* redirect to sign-in
  • x-tenant-slug header set from hostname parsing
  • /api/health, /api/auth/*, /_next/* bypass middleware
  • Existing auth flow unaffected (middleware is additive, not replacement)
  • npm run check passes
  • E2E auth tests still pass

Out of scope

  • Edge-level rate limiting (T-014 — requires Upstash Redis at edge)
  • CMS middleware (single-tenant, less benefit)
  • Geo-routing or A/B testing

Notes / decisions log

  • 2026-07-07: Proposed. Medium effort due to need for careful matcher config and testing auth edge cases (token refresh, OAuth callback).
  • 2026-07-09: Deferred — moved to tickets/deferred/; no active implementation planned.