Skip to main content

Route protection

Protect access in two places:

  1. Use createAuthMiddleware in Next.js proxy/middleware to verify credentials, refresh tokens when needed, and redirect unauthenticated page requests.
  2. Check authentication and resource permissions at every protected server boundary, before reading data or performing a mutation.

Proxy/middleware runs before matched routes. It improves the navigation flow, but does not replace checks in pages, API handlers, or Server Actions. Complete App Router setup or Pages Router setup before using these examples.

Choose protected routes​

Two configurations work together:

ConfigurationResponsibility
Next.js config.matcherSelects requests that run through proxy/middleware. Unmatched requests never reach this layer.
Blueprint appRoutesDetermines how matched dashboard, login, anonymous, and masquerade routes are handled. Matching a request alone does not make it protected.

For example, configure the dashboard and an intentionally public help page in your shared auth config. Retain any other options your application already uses:

lib/auth/config.ts
import { createAuthConfig } from "@krakentech/blueprint-auth";

export const authConfig = createAuthConfig({
appRoutes: {
dashboard: {
pathname: "/dashboard",
allowList: ["/dashboard/help"],
},
home: { pathname: "/" },
login: { pathname: "/login" },
},
});

The dashboard pathname covers its subroutes. allowList skips the dashboard route check for the listed paths; it does not grant access to protected data. Keep exceptions narrow. Configure localized paths through the i18n integration when needed.

Install proxy or middleware​

Use the file convention for your Next.js version, regardless of whether your pages use App Router or Pages Router. Place the file beside app/ or pages/, inside src/ if your application uses that directory.

proxy.ts
import { createAuthMiddleware } from "@krakentech/blueprint-auth/middleware";
import { authConfig } from "@/lib/auth/config";

export const proxy = createAuthMiddleware(authConfig);

export const config = {
matcher: ["/", "/((?!api|_next|_vercel|.*\\..*).*)"],
};

Next.js 16 proxy uses the Node.js runtime. Earlier middleware deployments may use Edge; keep imports compatible with the runtime you deploy to. Route protection is not inherently an Edge-only feature.

Matcher coverage​

Use the catch-all matcher above so auth runs on every page route, including public pages and localized paths. Do not restrict the matcher to dashboard, login, anonymous, or masquerade routes: appRoutes determines which matched pages require authentication. Running auth on public pages does not make them private.

The negative lookahead skips paths starting with api, _next, or _vercel and paths containing a dot, such as static files. If a real page path or dynamic segment falls under one of these exclusions, adjust the exclusion so auth still runs there. Do not exclude a page just because it is public.

The explicit "/" entry is required only for Pages Router projects using Next.js's built-in i18n option in next.config.*. In those projects, it covers locale roots without a trailing slash, such as /en and /fr, which the regex alone does not match.

If your project does not use that option, the regex already covers these routes and you can omit the "/" entry. This includes App Router projects using next-intl. The examples retain the entry to work with either setup. Blueprint Auth's own i18n configuration does not require it.

API routes, Route Handlers, and Server Actions still need their own authentication and authorization checks before accessing protected data or performing mutations. Page or layout checks are not sufficient because these entry points can be invoked directly.

The catch-all already covers ordinary anonymous and masquerade entry paths; configure their behavior in appRoutes rather than adding a matcher for each one.

Check auth at the server boundary​

Use the server functions exported by your router's setup guide. These examples require a non-scoped session for a dashboard page and deny access before any protected data is fetched:

app/dashboard/page.tsx
import { BlueprintAuthErrorCode } from "@krakentech/blueprint-auth";
import { getAuth, redirectToLogin } from "@/lib/auth/server";

export default async function DashboardPage() {
const auth = await getAuth.user();

if (!auth || auth.session.authMethod === "scoped") {
return redirectToLogin({
errorCode: BlueprintAuthErrorCode.AuthenticationRequired,
});
}

return <h1>Dashboard</h1>;
}

Repeat the check inside every protected Server Action and Route Handler. A page or layout check does not protect an action that can be invoked directly.

redirectToLogin uses the configured login route and includes an error code, so the login page can render even when a scoped session is present.

After the guard, use getGraphQLClient.user({ auth }) for user-authenticated Kraken requests. Keep the auth context server-side: it contains the access token and must not be returned in page props or passed to Client Components.

getAuth.user() can also return a scoped session. A route intentionally supporting expiring URLs may accept it, but must enforce the limited resource access on the server. Ordinary dashboard routes reject scoped sessions unless also configured for anonymous access; see the anonymous authentication guide.

Verification and authorization​

Blueprint Auth verifies token signatures, trusted issuers, expiry, and required claims; checking whether a cookie exists is not sufficient. It can refresh a token using the available refresh credentials. See Session management for the lifecycle and verification configuration.

If verification keys are unavailable, proxy/middleware returns HTTP 503 rather than granting access. Do not catch server auth failures and continue with protected work, or treat every verification failure as a signed-out session.

A verified identity is not proof that the user may access every account or perform every operation. Enforce resource permissions on the server, and handle authorization failures from Kraken: it can still reject a token because of revocation, permissions, or account state.