KeyloomKeyloom
Keyloom Auth is currently in beta. Feedback and contributions are welcome!
Nextjs

Middleware

Protect routes and attach session context using Keyloom's Next.js middleware.

Middleware

Use Keyloom's middleware to protect pages and APIs, attach session context, and optionally run verification at the edge.

middleware.ts
import { createAuthMiddleware } from "@keyloom/nextjs/middleware";
import config from "@/keyloom.config";

export default createAuthMiddleware(config, {
  publicRoutes: ["/", "/sign-in", "/api/health"],
  verifyAtEdge: false,
  // routes: compiledManifest, // optional - for declarative gating
});

export const config = {
  matcher: ["/((?!_next|.*\\.(?:ico|png|jpg|svg|css|js|map)).*)"],
};

Options

  • publicRoutes: string[] - paths that do not require auth
  • verifyAtEdge: boolean - when true, verify JWT/session at the edge
  • routes - optional manifest to declare which routes require which roles

Behavior

  • Reads the incoming cookie token
  • Optionally verifies at edge and attaches lightweight auth hints
  • Redirects to your sign-in page if a protected page is accessed without a valid session
  • Works in both app and pages router

Patterns

  • Use publicRoutes to allow public marketing pages
  • Prefer server-side gating for sensitive APIs as an additional layer
  • Consider verifyAtEdge: true when you need early blocking and are using an edge-safe strategy (JWT + edge-safe adapter)

Troubleshooting

  • Ensure your matcher excludes Next.js internals and static assets
  • If redirects loop, verify baseUrl and cookie domain/path settings
  • In development, set cookie.secure: false

Prerequisites

  • keyloom.config.ts configured
  • Public sign-in route defined and included in publicRoutes
  • Correct matcher excluding Next internals and asset files

Advanced route matching

middleware.ts (advanced matcher)
export const config = {
  matcher: [
    // protect everything under /app except public
    "/app/:path*",
    // protect APIs except health
    "/api/(?!health).*",
  ],
};

Edge runtime compatibility

  • Works in Edge; avoid heavy DB calls in middleware
  • Use verifyAtEdge: true only with JWT strategy and cached JWKS
  • For APIs requiring DB, verify on the server handler instead

Error handling patterns

  • For pages: redirect to /sign-in when unauthenticated
  • For APIs: return JSON { error: 'unauthorized' } with 401
middleware.ts (API example)
export default createAuthMiddleware(config, {
  publicRoutes: ["/api/health"],
  onUnauthorized: (ctx) => {
    if (ctx.isApi)
      return new Response(JSON.stringify({ error: "unauthorized" }), {
        status: 401,
      });
    return Response.redirect(new URL("/sign-in", ctx.req.url));
  },
});

Performance tips

  • Keep publicRoutes precise to avoid extra work
  • Prefer a single lightweight cookie read and short-circuit where possible
  • Avoid per-request remote JWKS fetch; cache JWKS in memory

See also

Next steps

  • Add route-level role checks with server-side withRole

How is this guide?