Middleware
Protect Next.js routes at the edge with HelloJohn middleware — authentication checks, redirects, and role-based access in middleware.ts.
Middleware
HelloJohn's Next.js middleware protects routes at the edge before any page code runs. It validates JWTs from cookies or the Authorization header and redirects unauthenticated requests.
Setup
Create middleware.ts in your project root:
// middleware.ts
import { hellojohnMiddleware } from "@hellojohn/nextjs";
export default hellojohnMiddleware({
publicRoutes: ["/", "/sign-in", "/sign-up", "/about"],
loginUrl: "/sign-in",
});
export const config = {
matcher: [
// Match all routes except static files and Next.js internals
"/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)",
"/(api|trpc)(.*)",
],
};Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
publicRoutes | string[] | [] | Routes accessible without authentication |
loginUrl | string | "/sign-in" | Redirect URL for unauthenticated users |
afterSignInUrl | string | "/" | Redirect for already-authenticated users on auth pages |
ignoredRoutes | string[] | [] | Routes bypassed entirely by middleware |
debug | boolean | false | Log middleware decisions |
Public vs Protected Routes
export default hellojohnMiddleware({
// These routes are accessible without authentication
publicRoutes: [
"/",
"/pricing",
"/blog(.*)", // Wildcard: match /blog and all sub-paths
"/api/webhooks(.*)", // Public API endpoints
],
// Everything else requires authentication
loginUrl: "/sign-in",
});Routes not in publicRoutes automatically require authentication.
Accessing Auth State in Middleware
import { hellojohnMiddleware, getAuth } from "@hellojohn/nextjs";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export default hellojohnMiddleware(async (auth, req: NextRequest) => {
const { userId, sessionId, orgId, orgRole } = auth();
// Custom logic: require org membership for /app routes
if (req.nextUrl.pathname.startsWith("/app") && !orgId) {
return NextResponse.redirect(new URL("/select-org", req.url));
}
// Role-based access: /admin requires "admin" role
if (req.nextUrl.pathname.startsWith("/admin") && orgRole !== "admin") {
return NextResponse.redirect(new URL("/dashboard", req.url));
}
});Auth Object Properties
| Property | Type | Description |
|---|---|---|
userId | string | null | Authenticated user ID |
sessionId | string | null | Current session ID |
orgId | string | null | Active organization ID |
orgRole | string | null | User's role in the active org |
getToken() | () => Promise<string> | Get the access token for outgoing requests |
Protecting API Routes
Middleware protects API routes automatically. For API routes that should be public (e.g., webhooks), add them to ignoredRoutes:
export default hellojohnMiddleware({
publicRoutes: [...],
ignoredRoutes: [
"/api/webhooks",
"/api/health",
],
});Edge Runtime Compatibility
HelloJohn's middleware runs in Next.js Edge Runtime. It verifies JWTs locally using the JWKS public key (no round-trip to HelloJohn). This makes it fast (sub-millisecond) and works on Vercel Edge, Cloudflare Workers, and other edge platforms.
The middleware does not make network requests for token validation by default.