API reference
Check out our getting started guides:
See the migration guides for version-specific breaking changes and upgrade instructions.
Public entry points
Import each runtime export from the entry point in this table.
| Entry point | Runtime exports |
|---|---|
@krakentech/blueprint-auth | AUTH_COOKIE, AuthError, BlueprintAuthErrorCode, createAuthCacheProfiles, createAuthConfig, getErrorType, getKrakenErrorDetails, ignoredQueryParams, isKrakenErrorResponse, isMappedKrakenErrorCode, krakenAuthTokenOverrideHeader, krakenErrorTypeToCodeMap, nextPageParam, sessionQueryKey, xClientIpAuthorizationHeader, xClientIpHeader, xErrorPolicyHeader |
@krakentech/blueprint-auth/cache/global-config | createGlobalConfigCacheAdapter |
@krakentech/blueprint-auth/cache/memory | createMemoryCacheAdapter |
@krakentech/blueprint-auth/client | createClientSideAuth, redirectToNextPage |
@krakentech/blueprint-auth/middleware | createAuthCookieUtils, createAuthMiddleware, forwardHeaders |
@krakentech/blueprint-auth/server | createAppRouterAuth, createAuthCookieUtils, createGraphQLHandler, createKrakenOAuthHandler, createLoginHandler, createLogoutHandler, createServerSideAuth, createSessionHandler, createUpdateOrgTokenHandler, generateKrakenOAuthURI, getAuth, getGraphQLClient, getRequestPathname, getSession, login, logout, prefetchSession, redirectToLogin, validateGraphQLRequest |
@krakentech/blueprint-auth/utils | convertIterableToRecord, convertRecordToIterable, getErrorCode, isBlueprintAuthErrorCode, isUnauthenticatedError, setKrakenAuthTokenOverrideHeader, setNextPageSearchParam |
Configuration
The utility functions of the package all extend the same interface for static configuration options. This enables the use of a centralized configuration object that can be reused throughout the project.
The package provides a configuration factory, enabling auto-completion and type-checking of the configuration object.
createAuthConfig
Create a config object reusable throughout the project, and set compatible options with environment variables.
Configuration
Required options with an environment variable alternatives must be provided either via environment variables or directly in the config object.
- Kraken
- Encryption
- App Routes
- API Routes
- Customization
- Validation
- i18n
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
krakenConfig.authEndpoint | Auth endpoint for OAuth and verification keys | string | KRAKEN_AUTH_ENDPOINT | ✅ |
krakenConfig.graphqlAuthEndpoint | GraphQL endpoint for auth operations | string | KRAKEN_GRAPHQL_AUTH_ENDPOINT | ❌ Defaults to krakenConfig.graphqlEndpoint |
krakenConfig.graphqlEndpoint | Target GraphQL endpoint | string | KRAKEN_GRAPHQL_ENDPOINT | ✅ |
krakenConfig.oauthClientId | Kraken OAuth client ID | string | KRAKEN_OAUTH_CLIENT_ID | ⚠️ Required to enable Kraken OAuth |
krakenConfig.organizationSecretKey | Kraken organization secret key | string | KRAKEN_ORGANIZATION_KEY | ⚠️ Required to enable organization-scoped auth |
krakenConfig.xClientIpOverride | Override the client IP sent to Kraken | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
When Blueprint Auth resolves a client IP, it adds the x-kraken-client-ip-authorization and
x-kraken-client-ip headers. The first header contains the base 64 encoded value of
krakenConfig.xClientIpSecretKey. The second header contains the resolved client IP.
krakenConfig.xClientIpOverride takes precedence. Otherwise, Blueprint Auth uses the first address
in x-forwarded-for.
These headers are used by Kraken to attribute requests made from a limited number of IP addresses, e.g. server-side requests, to the actual user IP address, preventing erroneous rate-limiting. More information can be found on this Kraken announcement.
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
encryption.key | Encryption secret key | string | AUTH_ENCRYPTION_KEY | ⚠️ Required to enable organization-scoped auth |
Blueprint Auth creates a unique initialization vector for each organization token.
| Option | Description | Type | Required |
|---|---|---|---|
appRoutes.anon.allowList | Pathnames accessible without authentication. Supports glob patterns and dynamic segments. | readonly string[] | ❌ |
appRoutes.anon.customErrorResponse | Custom error response override | (options: { errorCode: [ErrorCode](#errorcode); url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.anon.customSuccessResponse | Custom success response override | (options: { url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.anon.getAnonParams | Extract pre-signed key from anon route URL | (options: { url: NextURL }) => { preSignedKey: string | null | undefined } | undefined | ⚠️ Required to enable anon auth |
appRoutes.anon.pathname | Pathnames of routes accessible using anon authentication. Supports glob patterns and dynamic segments. | string | readonly string[] | ⚠️ Required to enable anon auth |
appRoutes.dashboard.allowList | Pathnames accessible without authentication. Supports glob patterns and dynamic segments. | readonly string[] | ❌ |
appRoutes.masquerade.customErrorResponse | Custom error response override | (options: { errorCode: [ErrorCode](#errorcode); url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.masquerade.customSuccessResponse | Custom success response override | (options: { url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.masquerade.getMasqueradeParams | Extract user ID and masquerade token from masquerade route URL | (options: { url: NextURL }) => { masqueradeToken: string | null | undefined; userId: string | null | undefined } | undefined | ⚠️ Required to enable masquerade auth |
appRoutes.masquerade.pathname | Masquerade pathname. Supports glob patterns and dynamic segments. | string | ⚠️ Required to enable masquerade auth |
appRoutes.dashboard.customErrorResponse | Custom error response override | (options: { errorCode: [ErrorCode](#errorcode); url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.dashboard.customSuccessResponse | Custom success response override | (options: { url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.dashboard.pathname | Dashboard pathname. Static path only. | string | ✅ |
appRoutes.home.pathname | Home pathname. Redirect destination after logout. Static path only. | string | ✅ |
appRoutes.login.pathname | Login pathname. Static path only. | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
apiRoutes.graphql | GraphQL API endpoints | Record<string, string> | ⚠️ Required to enable Client Functions |
apiRoutes.krakenOAuth | Kraken OAuth API endpoint | string | ⚠️ Required to enable Kraken OAuth |
apiRoutes.login | Login API endpoint | string | ⚠️ Required to enable Client Functions |
apiRoutes.logout | Logout API endpoint | string | ⚠️ Required to enable Client Functions |
apiRoutes.session | Session API endpoint | string | ⚠️ Required to enable Client Functions |
| Option | Description | Type | Required |
|---|---|---|---|
customization.accessTokenRefreshThresholdSeconds | Set the proactive refresh threshold, in seconds, for eligible user access tokens | number | ❌ |
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
customization.getGraphQLErrorLogLevel | Select the log level for a GraphQL error | (context: AuthErrorLogContext) => "debug" | "error" | "info" | "warn" | undefined | ❌ |
customization.headersToForward | Select incoming headers to forward to Kraken | string[] | ❌ |
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
Set accessTokenRefreshThresholdSeconds to a whole number from 1 through 3599. The default is
60. Blueprint Auth starts a proactive refresh when the remaining whole seconds are less than or
equal to this value.
setCustomHeaders receives a mutable Headers object. Change that object. Blueprint Auth waits for
the callback before it resolves an auth context or sends an authentication request.
Blueprint Auth sets access-cookie expiry from the verified token and ignores custom expires
values. Omit maxAge for accessToken and MWAuthToken to preserve that lifetime. Changing cookie
lifetime does not extend token validity.
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
validation.accessTokenIssuers | Exact issuers trusted during access token verification | string[] | KRAKEN_ACCESS_TOKEN_ISSUERS (comma-separated) | ✅ |
validation.allowedRequestOrigins | Trusted origins for cookie-authenticated POST API handlers (CSRF protection) | string[] | ALLOWED_REQUEST_ORIGINS (comma-separated) | ❌ (Required for createLoginHandler, createLogoutHandler, and createGraphQLHandler) |
validation.preventGraphQLMutations | Prevent GraphQL mutations | (graphQLEndpoint: string) => boolean | ❌ Defaults to preventProductionGraphQLMutationsDuringDevelopment | |
validation.validateGraphQLEndpointUrl | Validate Kraken GraphQL endpoint URL | boolean | ❌ | |
validation.graphQLRequestValidationOptions | Validate declared Content-Length and query byte length (limitations) | { maxRequestBodySize?: number; maxQueryLength?: number } | ❌ Defaults: maxRequestBodySize 100 KB (102400 bytes), maxQueryLength 50 KB (51200 bytes) |
An issuer is the iss field in an access token. validation.accessTokenIssuers uses exact,
case-sensitive matching. A path or trailing slash changes the issuer. For OAuth, add token/ to the
exact Kraken auth endpoint.
krakenConfig.authEndpoint must use HTTPS. For local development, HTTP is accepted only for
localhost, 127.0.0.1, and [::1]. Blueprint Auth gets the verification keys from this endpoint.
See Session management for an overview of the session lifecycle.
List each HTTP or HTTPS origin that serves your app. Include the scheme, host, and optional port. Do
not include a path, query, or fragment. For example, use https://www.example.com and
http://localhost:3000.
You can set origins in config or via the ALLOWED_REQUEST_ORIGINS environment variable
(comma-separated, whitespace around entries is trimmed):
ALLOWED_REQUEST_ORIGINS="https://www.example.com,https://localhost:3000"
Config takes precedence over the environment variable when validation.allowedRequestOrigins is
provided.
createLoginHandler, createLogoutHandler, and
createGraphQLHandler require at least one of the Origin and Referer
headers. Each supplied header must resolve to an origin in this list.
The handler factories throw AuthMissingPropertiesError if the resolved list is empty.
createAuthConfig rejects entries that are not HTTP or HTTPS origins.
The validation.preventGraphQLMutations option defaults to
preventProductionGraphQLMutationsDuringDevelopment, which:
- Prevents accidental execution of GraphQL mutations on production endpoints during development
- Applies when the endpoint URL includes
.kraken.techor.energyANDNODE_ENVis set todevelopment - Can be customized by providing your own validation function
- Can be disabled by setting
validation.preventGraphQLMutationsto a function that always returnsfalse
| Option | Description | Type | Required |
|---|---|---|---|
i18n.localeCookie | Name of the cookie storing user's locale preference | string | ❌ |
i18n.getLocalizedPathname | Callback to resolve localized pathnames | (options: GetLocalizedPathnameOptions) => string | ⚠️ Required when i18n is set |
Check out the full i18n guide to learn more.
Route matching
The pathname and allowList options accept three route formats:
| Format | Example | Description |
|---|---|---|
| Static path | /dashboard | Matches the configured route and its subroutes |
| Next.js dynamic segment | /dashboard/[accountNumber] | Converts the dynamic segment to a glob |
| Glob pattern | /dashboard/* | Uses picomatch |
A route pathname includes its subroutes. An allowList entry does not add subroutes. Add /**
when an allowlist entry must include descendant routes.
appRoutes.dashboard.customSuccessResponse runs only after middleware successfully refreshes and
verifies an access token. It does not run when an existing credential grants access. Blueprint Auth
preserves the callback response body, status, destination, headers, and cookies when it adds auth
headers and refreshed cookies.
You can use all three formats in one configuration. Blueprint Auth converts Next.js dynamic segments to glob patterns before it matches a route:
| Pattern | Glob equivalent | Matches |
|---|---|---|
/dashboard/[accountNumber] | /dashboard/* | /dashboard/A-12345 |
/join/[...steps] | /join/** | /join/energy/signup |
/join/[[...steps]] | /join/** | /join or /join/energy/signup |
Use Next.js dynamic segment syntax to make the configured routes match your file structure. You do not need to convert these segments to glob patterns. See the i18n guide for information about localized dynamic routes.
appRoutes.dashboard.pathname, appRoutes.anon.pathname, and appRoutes.masquerade.pathname use
prefix matching, so all routes that start with the configured path are guarded. For example,
appRoutes.dashboard.pathname: "/dashboard" protects /dashboard, /dashboard/settings,
/dashboard/account/123, and so on. Use allowList to exempt specific sub-routes from
authentication.
appRoutes.dashboard.pathname, appRoutes.login.pathname, and appRoutes.home.pathname must use
static paths. The middleware redirects users to these routes (e.g. unauthenticated users to
login, authenticated users to dashboard), and a redirect requires a concrete URL. Dynamic segments
and glob patterns cannot be resolved for redirects because the middleware has no way to determine
the params.
This does not affect allowList entries or routes used only for matching
(appRoutes.anon.pathname, appRoutes.masquerade.pathname), which support all three formats.
Make sure your secrets are kept secure and available server-side only:
- Do not hardcode them in your codebase.
- Do not use environment variables starting with
NEXT_PUBLIC_.
Usage
Somewhere in your project, export the config object returned by
createAuthConfig.
import { createAuthConfig } from "@krakentech/blueprint-auth";
export const authConfig = createAuthConfig({ ... });
Middleware
createAuthMiddleware
The middleware protects routes that require authentication. It redirects unauthenticated users to
the login page and refreshes eligible, missing, or expired access tokens. It also handles masquerade
and anonymous authentication. It returns 503 Service Unavailable when verification keys are
unavailable.
We expose this function separately to avoid bundling code that is unsupported in Edge Runtime. Learn More.
If you change headers or cookies after authMiddleware, finalize the response with
forwardHeaders.
Configuration
- Kraken
- App Routes
- Customization
- Validation
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
krakenConfig.authEndpoint | Auth endpoint for OAuth and the public JSON Web Key Set (JWKS) | string | KRAKEN_AUTH_ENDPOINT | ✅ |
krakenConfig.graphqlAuthEndpoint | GraphQL endpoint for auth operations | string | KRAKEN_GRAPHQL_AUTH_ENDPOINT | ❌ Defaults to krakenConfig.graphqlEndpoint |
krakenConfig.graphqlEndpoint | Target GraphQL endpoint | string | KRAKEN_GRAPHQL_ENDPOINT | ✅ |
krakenConfig.oauthClientId | Kraken OAuth client ID | string | KRAKEN_OAUTH_CLIENT_ID | ⚠️ Required to enable Kraken OAuth |
krakenConfig.xClientIpOverride | Override the client IP sent to Kraken | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
appRoutes.anon.allowList | Pathnames accessible without authentication. Supports glob patterns and dynamic segments. | readonly string[] | ❌ |
appRoutes.anon.customErrorResponse | Custom error response override | (options: { errorCode: [ErrorCode](#errorcode); url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.anon.customSuccessResponse | Custom success response override | (options: { url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.anon.getAnonParams | Extract pre-signed key from anon route URL | (options: { url: NextURL }) => { preSignedKey: string | null | undefined } | undefined | ⚠️ Required to enable anon auth |
appRoutes.anon.pathname | Pathnames of routes accessible using anon authentication. Supports glob patterns and dynamic segments. | string | readonly string[] | ⚠️ Required to enable anon auth |
appRoutes.dashboard.allowList | Pathnames accessible without authentication. Supports glob patterns and dynamic segments. | readonly string[] | ❌ |
appRoutes.dashboard.customErrorResponse | Custom error response override | (options: { errorCode: [ErrorCode](#errorcode); url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.dashboard.customSuccessResponse | Custom success response override | (options: { url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.dashboard.pathname | Dashboard pathname. Static path only. | string | ✅ |
appRoutes.login.pathname | Login pathname. Static path only. | string | ✅ |
appRoutes.masquerade.customErrorResponse | Custom error response override | (options: { errorCode: [ErrorCode](#errorcode); url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.masquerade.customSuccessResponse | Custom success response override | (options: { url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | Promise<NextResponse | undefined> | ❌ |
appRoutes.masquerade.getMasqueradeParams | Extract user ID and masquerade token from masquerade route URL | (options: { url: NextURL }) => { masqueradeToken: string | null | undefined; userId: string | null | undefined } | undefined | ⚠️ Required to enable masquerade auth |
appRoutes.masquerade.pathname | Masquerade pathname. Supports glob patterns and dynamic segments. | string | ⚠️ Required to enable masquerade auth |
| Option | Description | Type | Required |
|---|---|---|---|
customization.accessTokenRefreshThresholdSeconds | Set the proactive refresh threshold, in seconds, for eligible user access tokens | number | ❌ |
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
i18n.localeCookie | Name of the cookie storing user's locale preference | string | ❌ |
i18n.getLocalizedPathname | Callback to resolve localized pathnames | (options: GetLocalizedPathnameOptions) => string | ❌ |
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
validation.accessTokenIssuers | Exact access token issuer list | string[] | KRAKEN_ACCESS_TOKEN_ISSUERS (comma-separated) | ✅ |
The auth endpoint must use HTTPS. For local development, HTTP is accepted only for localhost,
127.0.0.1, and [::1]. Issuer matching is case-sensitive. Paths and trailing slashes are
significant. For OAuth, add token/ to the exact Kraken auth endpoint.
Parameters
| Parameter | Type | Description |
|---|---|---|
config | AuthMiddlewareConfig | Route, Kraken, and verification configuration |
Usage
- Simple usage
- Composing middlewares
If your Next.js middleware only handles authentication, the function returned by
createAuthMiddleware can be exported directly as middleware:
import { createAuthMiddleware } from "@krakentech/blueprint-auth/middleware";
import { authConfig } from "@/lib/auth/config";
export const middleware = createAuthMiddleware(authConfig);
export const config = {
matcher: ["/", "/((?!api|_next|_vercel|.*\\..*).*)"],
};
The auth middleware can be composed with other middlewares. Depending on which middleware needs to run first, you can either call the auth middleware first and pass its response to the next middleware, or vice-versa.
import type { NextRequest, NextResponse } from "next/server";
import { createAuthMiddleware } from "@krakentech/blueprint-auth/middleware";
import { authConfig } from "@/lib/auth/config";
const authMiddleware = createAuthMiddleware(authConfig);
function setCustomCookie({ res }: { res: NextResponse }) {
res.cookies.set("my-custom-cookie", "value");
return res;
}
export async function middleware(request: NextRequest) {
const res = await authMiddleware(request);
return setCustomCookie({ res });
}
export const config = {
matcher: ["/", "/((?!api|_next|_vercel|.*\\..*).*)"],
};
The auth middleware accepts an optional response parameter, which can be useful in case it needs to run after another middleware.
import type { NextRequest } from "next/server";
import { createAuthMiddleware } from "@krakentech/blueprint-auth/middleware";
import createIntlMiddleware from "next-intl/middleware";
import { authConfig } from "@/lib/auth/config";
import { routing } from "@/i18n/routing";
const intlMiddleware = createIntlMiddleware(routing);
const authMiddleware = createAuthMiddleware(authConfig);
export async function middleware(request: NextRequest) {
const response = await intlMiddleware(request);
if (!response.ok) return response;
return authMiddleware(request, response);
}
export const config = {
matcher: ["/", "/((?!api|_next|_vercel|.*\\..*).*)"],
};
If a middleware returns a redirect or a rewrite response, decide whether to skip other middlewares.
The Location header identifies redirects only. Next.js middleware rewrites use the
x-middleware-rewrite header.
forwardHeaders
Forwards request headers to Server Components and getServerSideProps while preserving response
headers and cookies. Redirect and error responses are returned unchanged.
The auth middleware calls this internally, you only need to use it if you mutate headers or cookies after the auth middleware.
| Parameter | Type | Description |
|---|---|---|
request | NextRequest | The incoming request |
response | NextResponse | The middleware response to finalize |
Returns: The finalized NextResponse.
Usage
Call forwardHeaders after your post-auth changes. To set a request header for downstream handlers,
use x-middleware-request-<name> as shown below. Setting an ordinary response header does not
change the downstream request:
import type { NextRequest, NextResponse } from "next/server";
import { createAuthMiddleware, forwardHeaders } from "@krakentech/blueprint-auth/middleware";
import createIntlMiddleware from "next-intl/middleware";
import { authConfig } from "@/lib/auth/config";
import { routing } from "@/i18n/routing";
const intlMiddleware = createIntlMiddleware(routing);
const authMiddleware = createAuthMiddleware(authConfig);
function setCustomCookie({ res }: { res: NextResponse }) {
res.cookies.set("my-custom-cookie", "value");
return res;
}
export async function middleware(request: NextRequest) {
let response = await intlMiddleware(request);
if (!response.ok) return response;
response = await authMiddleware(request, response);
if (!response.ok) return response;
// Set the downstream request header, including any existing override.
response.headers.set("x-middleware-request-x-custom-header", "updated-value");
response = setCustomCookie({ res: response });
return forwardHeaders(request, response);
}
export const config = {
matcher: ["/", "/((?!api|_next|_vercel|.*\\..*).*)"],
};
Server Functions
The package exports Server Functions, which can be used in Next.js server-side execution contexts.
These functions can either be used directly, passing all required configuration and context parameters on each call, or via factories.
Server functions typically accept two separate parameter objects:
- Static Configuration: Application settings that rarely change (endpoints, secrets, routes).
Pass your
authConfigobject directly. - Runtime Parameters: Dynamic values for each call (context, user input, etc.)
// Direct call: pass configuration and request values.
await login(authConfig, {
context,
input: { email, password },
});
// Factory call: pass only request values.
await login({ context, input: { email, password } });
A factory function adds the configuration for you.
Execution environment
Not all functions work in all environments. Use the table below to check compatibility.
| Function | SSG | SSR | API Handler | Route Handler | Server Component | Server Action | Middleware |
|---|---|---|---|---|---|---|---|
createAuthCookieUtils | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
generateKrakenOAuthURI | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
getAuth | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
getGraphQLClient | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
getRequestPathname | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
getSession | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
login | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ |
logout | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ |
prefetchSession | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
redirectToLogin | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
The context object
Request-bound Server Functions expect a context object in Pages Router code. Its shape varies with
the execution context. getGraphQLClient.* accepts a resolved auth context instead.
- SSG
- SSR
- API Handler
- Server Component
- Route Handler
- Middleware
type StaticPropsContext = GetStaticPropsContext;
import type { GetStaticPropsContext } from "next";
export async function getStaticProps(context: GetStaticPropsContext) {
// Pass context to supported server functions.
}
type ServerSidePropsContext = GetServerSidePropsContext;
import type { GetServerSidePropsContext } from "next";
export async function getServerSideProps(context: GetServerSidePropsContext) {
...
}
type ApiRouteHandlerContext = { req: NextApiRequest; res: NextApiResponse };
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const context = { req, res };
...
}
Use the createAppRouterAuth helper to get pre-configured Server
Functions with the context object already set.
type ServerComponentContext = {
cookies(): Promise<ReadonlyRequestCookies>;
headers(): Promise<ReadonlyHeaders>;
};
import { cookies, headers } from "next/headers";
const context = { cookies, headers };
In Server Components, cookies() and headers() are read-only. Write operations on cookies are
only allowed in Server Actions, they throw an error in Server Components. Runtime behavior differs
depending on the execution environment, even though types are identical.
type RouteHandlerContext = { req: NextRequest };
export async function POST(req: NextRequest) {
const context = { req };
...
}
type MiddlewareContext = { req: NextRequest; res: NextResponse };
export async function middleware(req: NextRequest) {
// if you have a `NextResponse` object from a previous operation:
const context = { req, res };
// if you don't have a `NextResponse` object, create one with `NextResponse.next()`:
const context = { req, res: NextResponse.next() };
...
}
At the TypeScript level, Server Actions and Server Components share the same context type since they
use the same Next.js APIs (cookies() and headers()). However, we distinguish them with separate
type names:
ServerComponentContextis used for React Server Components (RSC).ServerActionContextis used for Server Actions.
This distinction helps clarify where each function can be used, even though the underlying type is identical.
Server cache dependency
AuthConfig does not contain cache credentials. If you use organization auth, create the cache
adapter in a module that browser code cannot import. Pass it to direct organization auth functions
and handlers, or bind it with a server factory. Blueprint Auth uses the adapter for encrypted
organization credentials. User and viewer auth, sessions, login, logout, and OAuth do not require an
adapter, including when accessed through a server factory.
In an App Router application, add import "server-only"; as the first line of the cache module.
Pages Router does not support this marker. In a Pages Router application, import the cache module
only from getServerSideProps, API Routes, and other server modules. Do not import it from a
component or client module.
createGlobalConfigCacheAdapter
Blueprint Auth provides an optional Vercel Global Config adapter. Install its peer dependency, then create one adapter at module scope:
pnpm add @vercel/global-config
import { createGlobalConfigCacheAdapter } from "@krakentech/blueprint-auth/cache/global-config";
export const cacheAdapter = createGlobalConfigCacheAdapter();
The adapter reads GLOBAL_CONFIG, VERCEL_AUTH_TOKEN, and VERCEL_TEAM_ID when it is created. It
falls back to the legacy EDGE_CONFIG variable when GLOBAL_CONFIG is absent. Creation
synchronously checks that all values are present. It also parses the store ID and creates the Global
Config client. The provider checks authentication and access when the adapter reads or writes data.
You can override individual values:
const cacheAdapter = createGlobalConfigCacheAdapter({
authToken: process.env.CUSTOM_VERCEL_AUTH_TOKEN,
});
| Option | Default | Purpose |
|---|---|---|
authToken | process.env.VERCEL_AUTH_TOKEN | Vercel API token for writes |
envVar | process.env.GLOBAL_CONFIG ?? process.env.EDGE_CONFIG | Global Config connection string and read token |
teamId | process.env.VERCEL_TEAM_ID | Team that owns the Global Config store |
All reads use the connection credentials from envVar. Writes require authToken and teamId.
createMemoryCacheAdapter
Use the memory adapter for local development and isolated tests:
import { createMemoryCacheAdapter } from "@krakentech/blueprint-auth/cache/memory";
const cacheAdapter = createMemoryCacheAdapter();
Each call creates an isolated process-local store. The adapter accepts and ignores bypassCache
because every read reaches the same store.
Values do not survive a process restart and are not shared with other application instances. In cloud environments, each instance and cold start begins with an empty cache. This can repeat network requests that a shared cache avoids.
Use the memory adapter only for local development and isolated tests.
Custom adapter contract
Import AuthCacheAdapter and AuthCacheValue from the package root:
import type { AuthCacheAdapter, AuthCacheValue } from "@krakentech/blueprint-auth";
An AuthCacheAdapter stores authentication data on the server. get(key) can use the provider's
normal read cache. get(key, { bypassCache: true }) asks the adapter to bypass an additional cache
layer when it has one. An adapter can ignore the hint when every read already reaches its backing
store, such as with a direct Redis adapter.
Both read modes return undefined when the key does not exist. null is a valid stored value. Read
failures must reject. set(key, value) must resolve only after the adapter accepts the write. Write
failures must reject.
AuthCacheValue supports strings, finite numbers, booleans, null, arrays of supported values, and
objects whose values are supported. Do not store undefined, functions, symbols, bigint, class
instances, or other non-JSON data.
Production adapters must use a backing store shared by application instances that use the same organization credentials. Use a process-local store only for local development and isolated tests.
Server Function Factories
Server Functions can be used in three different ways, depending on your particular needs.
createServerSideAuth(config, params = {}) accepts an optional cacheAdapter.
createAppRouterAuth(config, { cache, cookies, headers, cacheAdapter }) requires cache,
cookies, and headers, but cacheAdapter is optional.
Without an adapter, both factories support user and viewer auth, sessions, login, logout, and OAuth.
Calling a factory's getAuth.org without an adapter fails with AuthMissingPropertiesError for
cacheAdapter. Direct getAuth.org calls and organization token handlers still require an adapter.
| Method | Description | Recommendation | Needs configuration | Needs context |
|---|---|---|---|---|
| Direct | Import each function from the package | One call or advanced use | ✅ | ✅ |
| Server-side | Bind configuration and the cache adapter | Pages Router | ❌ | ✅ |
| App Router | Bind configuration, the cache adapter, and context | App Router | ❌ | ❌ |
- Direct
- Server-side
- App Router
Pass configuration and request values to each direct function. Pass the cache adapter to direct organization auth functions. Pass resolved auth contexts directly to GraphQL clients.
import {
createAuthCookieUtils,
generateKrakenOAuthURI,
getAuth,
getGraphQLClient,
getRequestPathname,
getSession,
login,
logout,
prefetchSession,
} from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
const {
getAuthCookie,
getAuthCookies,
getAuthTokenOverride,
removeAllCookies,
removeAuthCookies,
removeAuthTokenCookies,
setAuthCookie,
} = createAuthCookieUtils(authConfig, { context });
await generateKrakenOAuthURI(authConfig, { context });
await getRequestPathname({ context });
await getSession(authConfig, { context });
await login(authConfig, {
context,
input: { email, password },
});
await logout(authConfig, { context });
await prefetchSession(authConfig, { context, queryClient });
const auth = await getAuth.user(authConfig, { context });
if (auth) getGraphQLClient.user(authConfig, { auth });
Server Functions returned by createServerSideAuth do not need the
configuration or cache adapter objects. Pass the context object and other runtime parameters only.
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const {
createAuthCookieUtils,
generateKrakenOAuthURI,
getAuth,
getGraphQLClient,
getRequestPathname,
getSession,
login,
logout,
prefetchSession,
redirectToLogin,
} = createServerSideAuth(authConfig, { cacheAdapter });
const {
getAuthCookie,
getAuthCookies,
getAuthTokenOverride,
removeAllCookies,
removeAuthCookies,
removeAuthTokenCookies,
setAuthCookie,
} = createAuthCookieUtils({ context });
await generateKrakenOAuthURI({ context });
await getRequestPathname({ context });
await getSession({ context });
await login({ context, input: { email, password } });
await logout({ context });
await prefetchSession({ context, queryClient });
const auth = await getAuth.user({ context });
if (auth) getGraphQLClient.user({ auth });
Server Functions returned by createAppRouterAuth do not need the
configuration, cache adapter, or context objects. Pass runtime parameters only. The factory
requires cache, cookies, and headers. Pass cacheAdapter only if you use getAuth.org.
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const {
// cookie utilities
getAuthCookie,
getAuthCookies,
getAuthTokenOverride,
removeAllCookies,
removeAuthCookies,
removeAuthTokenCookies,
setAuthCookie,
// auth and GraphQL clients
getAuth,
getGraphQLClient,
// server functions
generateKrakenOAuthURI,
getRequestPathname,
getSession,
login,
logout,
prefetchSession,
redirectToLogin,
} = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
await generateKrakenOAuthURI();
await getRequestPathname();
await getSession();
await login({
input: { email, password },
searchParams, // Pass the login page searchParams Promise.
});
await logout();
await prefetchSession({ queryClient });
const auth = await getAuth.user();
if (auth) getGraphQLClient.user({ auth });
Next.js 16.3 applications that enable Partial Prefetching should use private authentication reads. Follow the Partial Prefetching setup.
- Client components
- React's cache utility
- Blocking calls
Do not add "use server" to lib/auth/server.ts. The factory also returns synchronous functions.
Next.js does not permit synchronous exports in a Server Action module.
Create a separate action module for functions that a Client Component calls:
"use server";
import { logout as logoutImpl } from "./server";
export async function logout() {
return await logoutImpl();
}
"use client";
import { logout } from "@/lib/auth/actions";
export function LogoutButton() {
return (
<button type="button" onClick={() => logout()}>
Log out
</button>
);
}
Pass React's cache function to
createAppRouterAuth. The factory wraps the functions shown below.
React can reuse a result when a component render calls a wrapped function again with the same
argument references.
| Function | Cached |
|---|---|
generateKrakenOAuthURI | ✅ |
getAuth.* | ✅ |
getAuthCookie | ✅ |
getAuthCookies | ✅ |
getAuthTokenOverride | ✅ |
getGraphQLClient.* | ✅ |
getRequestPathname | ✅ |
getSession | ✅ |
login | ❌ |
logout | ❌ |
prefetchSession | ✅ |
redirectToLogin | ❌ |
removeAllCookies | ❌ |
removeAuthCookies | ❌ |
removeAuthTokenCookies | ❌ |
setAuthCookie | ❌ |
The client request method is not wrapped with React cache. Each call can send a network request.
Wrap a query function with cache when one render must deduplicate identical work.
import type { AuthContext } from "@krakentech/blueprint-auth/server";
import { cache } from "react";
import { getGraphQLClient } from "@/lib/auth/server";
import { graphql } from "@/lib/graphql";
const UserQuery = graphql(`
query User {
viewer {
dateOfBirth
email
familyName
fullName
givenName
mobile
preferredName
title
}
}
`);
export const getUser = cache(async (auth: AuthContext.User) => {
const graphQLClient = getGraphQLClient.user({ auth });
const { viewer } = await graphQLClient.request(UserQuery);
return viewer;
});
The App Router factory also applies React cache to each client scope. The auth context reference
and error policy form the arguments. Repeated calls with the same references can return the same
BlueprintGraphQLClient during one render. Each operation still sends
its own GraphQL request.
Calls to asynchronous function in Server Components block the rendering process and may harm the
performances of your application. Make sure Server Functions are called in components wrapped in
Suspense boundary to display a fallback while the
asynchronous operation is in progress and stream the content once the function resolves.
import { Button, DropdownMenu } from "@radix-ui/themes";
import Link from "next/link";
import { Avatar } from "@/components/Avatar";
import { LogoutButton } from "@/components/LogoutButton";
import { getAuth } from "@/lib/auth/server";
import { getUser } from "@/queries/getUser";
export async function UserMenu() {
const auth = await getAuth.user();
if (!auth) {
return (
<Button asChild>
<Link href="/login">Log in</Link>
</Button>
);
}
const { givenName, preferredName } = await getUser(auth);
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<Avatar name={preferredName || givenName} />
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item asChild>
<Link href="/dashboard/settings">Settings</Link>
</DropdownMenu.Item>
<DropdownMenu.Item asChild>
<LogoutButton />
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>
);
}
import { Suspense } from "react";
import { Logo } from "@/components/Logo";
import { NavigationMenu } from "@/components/NavigationMenu";
import { Skeleton } from "@/components/Skeleton";
import { UserMenu } from "@/components/UserMenu";
function Header() {
return (
<header>
<NavigationMenu />
<Logo />
<Suspense fallback={<Skeleton />}>
<UserMenu />
</Suspense>
</header>
);
}
generateKrakenOAuthURI
Set the code verifier cookie, and generate a unique URI to initiate the Kraken OAuth flow.
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
apiRoutes.krakenOAuth | OAuth callback API route | string | ✅ |
krakenConfig.authEndpoint | Kraken auth endpoint | string | ✅ |
krakenConfig.oauthClientId | Kraken OAuth client ID | string | ✅ |
Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
context | Request context | ServerSidePropsContext | ApiRouteHandlerContext | RouteHandlerContext | ServerActionContext | MiddlewareContext | ✅ |
Output
| Type | Description |
|---|---|
Promise<string> | The generated Kraken OAuth URI |
Usage
- Direct
- Server-side
- App Router
import { generateKrakenOAuthURI } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
const krakenOAuthURI = await generateKrakenOAuthURI(authConfig, { context });
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { generateKrakenOAuthURI } = createServerSideAuth(authConfig, {
cacheAdapter,
});
import { generateKrakenOAuthURI } from "@/lib/auth/server";
const krakenOAuthURI = await generateKrakenOAuthURI({ context });
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { generateKrakenOAuthURI } = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import { generateKrakenOAuthURI } from "@/lib/auth/server";
const krakenOAuthURI = await generateKrakenOAuthURI();
getSession
Select and verify one user token. Return session data from the verified token fields. See Session management for a session lifecycle overview.
Configuration
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
customization.accessTokenRefreshThresholdSeconds | Proactive access token refresh threshold | number | ❌ Defaults to 60 | |
customization.getCookieOptions | Cookie options used when writing a replacement access token | function | ❌ | |
customization.headersToForward | Incoming headers to include in authentication refresh requests | string[] | ❌ | |
customization.setCustomHeaders | Add headers to authentication refresh requests | function | ❌ | |
krakenConfig.authEndpoint | Auth endpoint for verification keys and OAuth refresh | string | KRAKEN_AUTH_ENDPOINT | ✅ |
krakenConfig.graphqlAuthEndpoint | GraphQL endpoint for email and mobile refresh | string | KRAKEN_GRAPHQL_AUTH_ENDPOINT | ❌ Defaults to krakenConfig.graphqlEndpoint |
krakenConfig.oauthClientId | OAuth client ID used for OAuth refresh | string | KRAKEN_OAUTH_CLIENT_ID | ⚠️ Required for OAuth refresh |
krakenConfig.xClientIpOverride | Override the client IP sent during email and mobile refresh | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key used to sign the client IP during email/mobile refresh | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
validation.accessTokenIssuers | Exact trusted access token issuers | string[] | KRAKEN_ACCESS_TOKEN_ISSUERS | ✅ |
Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
params.context | Request context | ServerSidePropsContext | ApiRouteHandlerContext | RouteHandlerContext | ServerComponentContext | ServerActionContext | MiddlewareContext | ✅ |
Output
Returns a SessionState object:
| Field | Description | Type |
|---|---|---|
authMethod | Method from the verified gty field | AuthMethod | null |
authSource | Location of the selected token | AuthSource | null |
isAuthenticated | The request has a verified user token | boolean |
sub | User ID from the verified sub field | string | null |
Usage
- Direct
- Server-side
- App Router
import { getSession } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
const session = await getSession(authConfig, { context });
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getSession } = createServerSideAuth(authConfig, {
cacheAdapter,
});
import { getSession } from "@/lib/auth/server";
const session = await getSession({ context });
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getSession } = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import { getSession } from "@/lib/auth/server";
const session = await getSession();
login
Authenticate a user with an email address and password. Redirect the user after successful authentication unless you disable the redirect.
Configuration
- Kraken
- App Routes
- Customization
- i18n
- Validation
| Option | Description | Type | Required |
|---|---|---|---|
krakenConfig.authEndpoint | Auth endpoint for verification keys | string | ✅ |
krakenConfig.graphqlAuthEndpoint | GraphQL endpoint for auth operations | string | ✅ |
krakenConfig.xClientIpOverride | Override the client IP sent to Kraken | string | ❌ |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
appRoutes.dashboard.pathname | Dashboard pathname | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
| Option | Description | Type | Required |
|---|---|---|---|
i18n.localeCookie | Name of the cookie storing user's locale preference | string | ❌ |
i18n.getLocalizedPathname | Callback to resolve localized pathnames | (options: GetLocalizedPathnameOptions) => string | ❌ |
| Option | Description | Type | Required |
|---|---|---|---|
validation.accessTokenIssuers | Exact trusted access token issuers | string[] | ✅ |
Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
context | Request context | ApiRouteHandlerContext | RouteHandlerContext | ServerActionContext | ✅ |
input | Login credentials | { email: string; password: string; captchaResponse?: string } | ✅ |
nextPage | Redirect pathname | string | null | ❌ |
enableRedirect | Enable redirect | boolean | ❌ Only available in API Handlers and Route Handlers |
searchParams | URL search parameters | SearchParams | Promise<SearchParams> | ✅ Only available in Server Actions |
Output
The return type of this function varies depending on the execution context.
- API Handler
- Route Handler
- Server Action
| Type | Condition |
|---|---|
Promise<undefined> | Always |
| Type | Condition |
|---|---|
Promise<NextResponse> | Always |
| Type | Condition |
|---|---|
Promise<never> | Throws a redirect by default |
Promise<undefined> | When nextPage is null |
Usage
- Direct
- Server-side
- App Router
import { login } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
await login(authConfig, {
context,
input: { email: "test@example.com", password: "****" },
nextPage: "/dashboard/settings",
searchParams, // available as props in Next.js App Router page components
});
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { login } = createServerSideAuth(authConfig, { cacheAdapter });
import { login } from "@/lib/auth/server";
await login({
context,
input: { email: "test@example.com", password: "****" },
nextPage: "/dashboard/settings",
searchParams, // available as props in Next.js App Router page components
});
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { login } = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import { login } from "@/lib/auth/server";
await login({
input: { email: "test@example.com", password: "****" },
nextPage: "/dashboard/settings",
searchParams, // available as props in Next.js App Router page components
});
After a successful login, if you do not set nextPage, the function uses the nextPage URL search
parameter. It uses appRoutes.dashboard.pathname as the fallback. To disable the success redirect,
set nextPage to null. This does not suppress a failure redirect when enableRedirect is true.
Redirection is disabled by default in API Handlers and Route Handlers. To enable redirects, set
the enableRedirect option to true.
Learn more
A Pages Router fetch does not start a client navigation from a redirect response. The browser follows the redirect and can lose client state. By default, the handler returns the redirect URL in JSON. The caller controls the navigation.
However, this behavior does not fit all use cases. For instance, a redirect response is desirable
when the API endpoint is used as the action attribute of the HTML <form> element. To enable
redirects, set the enableRedirect option. Use the login function in an App Router
Server Action. For the Pages Router, see the
login form guide.
Authentication failures throw by default. In API routes and Route Handlers, enableRedirect: true
redirects handled login failures to the referring page with an error query parameter. Other
failures, such as unavailable verification keys, still throw.
createLoginHandler returns HTTP error responses for thrown errors.
Learn more
Since Next.js 15, calling redirect in a Server Action results in a 303 See Other status
response. The App Router handles this error code with a client-side navigation, preserving the state
of layout components. However,
redirecting to the same page triggers a full page reload,
losing client-side page state in the process.
Handling errors client-side prevents the progressive enhancements enabled by Server Actions. If
you're using the App Router, consider storing form errors and validation errors as action state
using React's useActionState hook. Check out
the Next.js documentation to learn more.
logout
Remove authentication cookies. Redirect the user to the home page unless you disable the redirect.
For an OAuth session, Blueprint Auth first tries the upstream logout and token revocation requests. It logs an upstream failure and continues to remove local cookies. A local cookie removal failure still fails the logout operation.
Configuration
- App Routes
- Customization
- Kraken
- i18n
| Option | Description | Type | Required |
|---|---|---|---|
appRoutes.home.pathname | Home pathname | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
| Option | Description | Type | Required |
|---|---|---|---|
krakenConfig.authEndpoint | Kraken auth endpoint | string | ⚠️ Required for OAuth logout |
krakenConfig.oauthClientId | Kraken OAuth client ID | string | ⚠️ Required for OAuth logout |
krakenConfig.xClientIpOverride | Override the client IP sent to Kraken | string | ❌ |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
i18n.localeCookie | Name of the cookie storing user's locale preference | string | ❌ |
i18n.getLocalizedPathname | Callback to resolve localized pathnames | (options: GetLocalizedPathnameOptions) => string | ❌ |
Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
context | Request context | ApiRouteHandlerContext | RouteHandlerContext | ServerActionContext | ✅ |
nextPage | Redirect pathname | string | null | ❌ |
enableRedirect | Enable redirect | boolean | ❌ Only available in API Handlers and Route Handlers |
Output
The return type of this function varies depending on the execution context.
- API Handler
- Route Handler
- Server Action
| Type | Condition |
|---|---|
Promise<undefined> | Always |
| Type | Condition |
|---|---|
Promise<NextResponse> | Always |
| Type | Condition |
|---|---|
Promise<never> | Throws a redirect by default |
Promise<undefined> | When nextPage is null |
Usage
- Direct
- Server-side
- App Router
import { logout } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
await logout(authConfig, { context, nextPage: "/goodbye" });
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { logout } = createServerSideAuth(authConfig, { cacheAdapter });
import { logout } from "@/lib/auth/server";
await logout({ context, nextPage: "/goodbye" });
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { logout } = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import { logout } from "@/lib/auth/server";
await logout({ nextPage: "/goodbye" });
If the nextPage option is not set, appRoutes.home.pathname is used as the default redirect. To
disable redirection, set the nextPage option to null.
Redirection is disabled by default in API Handlers and Route Handlers. To enable redirects, set
the enableRedirect option to true.
Learn more
A Pages Router fetch does not start a client navigation from a redirect response. The browser follows the redirect and can lose client state. By default, the handler returns the redirect URL in JSON. The caller controls the navigation.
However, this behavior does not fit all use cases. For instance, a redirect response is desirable
when the API endpoint is used as the action attribute of the HTML <form> element. To enable
redirects, set the enableRedirect option.
prefetchSession
Selects and verifies one user token. Stores the resulting session in a QueryClient.
prefetchSession must be used in combination with the HydrationBoundary
component from @tanstack/react-query. To set it up with the Pages Router, check out the
Server Rendering and Hydration guide.
To learn more about the App Router setup, check out the
Advanced Server Rendering guide.
Configuration
This function uses krakenConfig.authEndpoint and validation.accessTokenIssuers for token
verification.
Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
context | Request context | ServerComponentContext | ServerSidePropsContext | StaticPropsContext | ✅ |
queryClient | @tanstack/react-query client instance | QueryClient | ✅ |
Output
| Type | Description |
|---|---|
Promise<void> | No return value |
Usage
- Direct
- Server-side
- App Router
import { prefetchSession } from "@krakentech/blueprint-auth/server";
import { QueryClient } from "@tanstack/react-query";
import { authConfig } from "@/lib/auth/config";
const queryClient = new QueryClient();
await prefetchSession(authConfig, { context, queryClient });
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { prefetchSession } = createServerSideAuth(authConfig, {
cacheAdapter,
});
import { QueryClient } from "@tanstack/react-query";
import { prefetchSession } from "@/lib/auth/server";
const queryClient = new QueryClient();
await prefetchSession({ context, queryClient });
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { prefetchSession } = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import { QueryClient } from "@tanstack/react-query";
import { prefetchSession } from "@/lib/auth/server";
const queryClient = new QueryClient();
await prefetchSession({ queryClient });
getRequestPathname
Get the page pathname associated with a request.
Configuration
This function does not require static configuration.
Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
context | Request context | ServerSidePropsContext | ApiRouteHandlerContext | RouteHandlerContext | ServerComponentContext | ServerActionContext | MiddlewareContext | ✅ |
Output
| Type | Description |
|---|---|
Promise<string | null> | Page pathname, or null when no referring page is available |
In API routes and Route Handlers, this is the referring page's pathname, not the endpoint's. Server rendering and Server Actions require auth middleware to run for the route; otherwise, the function throws.
Usage
- Direct
- Server-side
- App Router
import { getRequestPathname } from "@krakentech/blueprint-auth/server";
const pathname = await getRequestPathname({ context });
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getRequestPathname } = createServerSideAuth(authConfig, {
cacheAdapter,
});
import { getRequestPathname } from "@/lib/auth/server";
const pathname = await getRequestPathname({ context });
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getRequestPathname } = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import { getRequestPathname } from "@/lib/auth/server";
const pathname = await getRequestPathname();
redirectToLogin
Redirect to the configured login route from a server context. The function adds errorCode as the
error search parameter. It uses the current request pathname as nextPage by default. Pass
nextPage: null to omit that parameter.
| Context | Result |
|---|---|
| API Route | Calls res.redirect() and resolves to undefined |
| Route Handler | Returns NextResponse.redirect() |
| Server Component or Server Action | Calls redirect() and does not return |
getServerSideProps | Returns a nonpermanent redirect object |
The function supports API Routes, Route Handlers, Server Components, Server Actions, and
getServerSideProps. It does not support SSG or Middleware.
| Input | Type | Meaning |
|---|---|---|
appRoutes.login.pathname | string | Configured login route |
i18n | Auth i18n configuration | Optional localized login route support |
context | Supported server context | Request and response APIs |
errorCode | string | Required error search parameter |
nextPage | string | null | undefined | Explicit destination, no destination, or current pathname |
import { BlueprintAuthErrorCode } from "@krakentech/blueprint-auth";
import { redirectToLogin } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
return redirectToLogin(authConfig, {
context,
errorCode: BlueprintAuthErrorCode.AuthenticationRequired,
});
Factories bind configuration. The App Router factory also binds context. redirectToLogin reads
request state. Call it outside a "use cache" scope.
getAuth
Resolve request-specific credentials and headers into a server-only auth context. Call these
asynchronous functions outside "use cache" scopes.
| Function | Return type | Use when |
|---|---|---|
getAuth.viewer | Promise<AuthContext.Viewer> | Authentication is optional |
getAuth.user | Promise<AuthContext.User | null> | A local user credential is required |
getAuth.org | Promise<AuthContext.Org | null> | Organization credentials are required |
Session resolution
getAuth.viewer and getAuth.user select one authentication source in this order:
- Request access token override
- Mobile session from
MWAuthTokenand its optionalMWRefreshToken - Web session from
accessTokenand its optionalrefreshToken - Mobile session recovery from
MWRefreshToken - Web session recovery from
refreshToken
Blueprint Auth sends refresh tokens to Kraken only to obtain replacement access tokens.
The functions verify the replacement before use. The selected authentication source is final for the request. The functions do not try a lower priority source if the selected source cannot produce a valid session.
Eligible user sessions support proactive refresh. Blueprint Auth refreshes a valid token at the configured threshold. After a recoverable proactive failure, it tries again during each later auth resolution while the current token is valid. A rejected refresh token ends the local session. See Session management for the eligibility rules.
Blueprint Auth uses reactive refresh when an access token is missing or expired. Invalid signatures, issuers, claims, and grants end the selected local session.
getAuth.viewer always returns a context. Its session is null when the request has no verified
user. getAuth.user returns null in the same case. Both functions get identity and authMethod
from verified token fields. Kraken can still reject a verified token because of permissions,
revocation, or account state.
getAuth.org checks a request override first. The override must be a verified API-KEY token.
Without an override, the function checks the shared cache. It then checks the latest stored value.
If needed, it requests a token from Kraken. It verifies each value before use or storage.
See Session management for a session lifecycle overview.
The direct namespace exports getAuth.ViewerConfig, getAuth.ViewerParams, getAuth.UserConfig,
getAuth.UserParams, getAuth.OrgConfig, and getAuth.OrgParams.
Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
cacheAdapter | Shared cache for organization tokens | AuthCacheAdapter | getAuth.org only |
context | Request context | ServerSideContext | ✅ |
Resolved request values
Each context can contain the client IP, custom headers, and selected incoming headers. getAuth.*
resolves these values for the current request. It awaits customization.setCustomHeaders. It also
reads names in customization.headersToForward.
The client later removes reserved auth headers. It applies the resolved values to GraphQL requests. When the context is an argument to a cached function, all of these values participate in the cache key.
Usage
- Direct
- Server-side
- App Router
import { getAuth } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
const auth = await getAuth.user(authConfig, { context });
if (!auth) throw new Error("Authentication required.");
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getAuth } = createServerSideAuth(authConfig, { cacheAdapter });
import { getAuth } from "@/lib/auth/server";
const auth = await getAuth.user({ context });
if (!auth) throw new Error("Authentication required.");
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getAuth } = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import { getAuth } from "@/lib/auth/server";
const auth = await getAuth.user();
if (!auth) throw new Error("Authentication required.");
Auth contexts contain access tokens and can contain forwarded headers. Keep every context on the server and out of Client Components, browser code, logs, and public props.
Removed getUserScopedGraphQLClient
Use getAuth.user and then getGraphQLClient.user.
Removed getOrganizationScopedGraphQLClient
Use getAuth.org and then getGraphQLClient.org.
getGraphQLClient
Create a BlueprintGraphQLClient from a resolved auth context. Client
creation is synchronous. It does not read request APIs, so it can run inside "use cache" scopes.
| Function | Required auth type | Behavior |
|---|---|---|
getGraphQLClient.viewer | AuthContext.Viewer | Uses user credentials when present and supports an unauthenticated viewer |
getGraphQLClient.user | AuthContext.User | Requires an authenticated user context at type and runtime boundaries |
getGraphQLClient.org | AuthContext.Org | Requires organization credentials |
Request behavior
Direct calls use (config, { auth, errorPolicy? }). Factory calls use ({ auth, errorPolicy? }).
errorPolicy defaults to "none". The selected policy changes the return type of
client.request().
Each client operation sends one GraphQL request. The client applies the selected error policy to the response. Resolve auth before you create the client.
An operation can provide x-kraken-auth-token-override in its request headers. The client converts
that value to the outgoing authorization header. It does not forward the override header itself.
Other operation headers are limited to names in customization.headersToForward. The client removes
reserved auth headers. The auth context supplies the token, client IP, and resolved headers.
The direct namespace exports getGraphQLClient.Config and these parameter types:
getGraphQLClient.ViewerParams<Policy>, getGraphQLClient.UserParams<Policy>, and
getGraphQLClient.OrgParams<Policy>.
Parameters
| Parameter | Description | Type | Required |
|---|---|---|---|
auth | Context from the matching getAuth.* scope | AuthContext.Viewer | AuthContext.User | AuthContext.Org | ✅ |
errorPolicy | GraphQL error handling policy | "none" | "ignore" | "all" | ❌ |
Output
| Type | Description |
|---|---|
BlueprintGraphQLClient<Policy> | A GraphQL client for the selected auth scope. A viewer client can be unauthenticated. Policy is inferred from errorPolicy. |
Usage
- Direct
- Server-side
- App Router
import { getAuth, getGraphQLClient } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "@/lib/auth/cache";
import { authConfig } from "@/lib/auth/config";
const auth = await getAuth.org(authConfig, { cacheAdapter, context });
if (!auth) throw new Error("Organization authentication is unavailable.");
const graphQLClient = getGraphQLClient.org(authConfig, { auth });
const thirdPartyViewer = await graphQLClient.request(ThirdPartyViewerQuery);
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getAuth, getGraphQLClient } = createServerSideAuth(authConfig, {
cacheAdapter,
});
import { getAuth, getGraphQLClient } from "@/lib/auth/server";
const auth = await getAuth.org({ context });
if (!auth) throw new Error("Organization authentication is unavailable.");
const graphQLClient = getGraphQLClient.org({ auth });
const thirdPartyViewer = await graphQLClient.request(ThirdPartyViewerQuery);
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getAuth, getGraphQLClient } = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import { getAuth, getGraphQLClient } from "@/lib/auth/server";
const auth = await getAuth.org();
if (!auth) throw new Error("Organization authentication is unavailable.");
const graphQLClient = getGraphQLClient.org({ auth });
const thirdPartyViewer = await graphQLClient.request(ThirdPartyViewerQuery);
Kraken can reject a locally verified token after revocation or an account change. The GraphQL client
returns that authentication failure to the application. Applications can use
isUnauthenticatedError for an optional local session policy.
createAuthCookieUtils
Create helpers to manage authentication cookies.
Signature
function createAuthCookieUtils(
config: CreateAuthCookieUtilsConfig,
params: { context: ServerSideContext },
): AuthCookieUtils;
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
Output
Returns an object with the following fields:
| Field | Description | Type |
|---|---|---|
getAuthCookie | Get one auth cookie | (name: [CookieName](#cookiename)) => Promise<string | undefined> |
getAuthCookies | Get all managed auth cookies | () => Promise<[CookieMap](#cookiemap)> |
getAuthTokenOverride | Get the request token override header | () => Promise<{ token: string, type: "override" } | null> |
removeAllCookies | Remove all managed session cookies | () => Promise<void> |
removeAuthCookies | Remove named auth cookies | (cookies: [CookieName](#cookiename)[]) => Promise<void> |
removeAuthTokenCookies | Remove accessToken and MWAuthToken | () => Promise<void> |
setAuthCookie | Set one auth cookie | ({ name, value, expires? }: { name: [CookieName](#cookiename), value: string, expires?: Date }) => Promise<void> |
See CookieName and CookieMap in the Types section for type
definitions.
setAuthCookie stores cookies without verifying tokens. For accessToken and MWAuthToken, the
supplied expires takes precedence over custom cookie options; for other cookies, the custom
expires wins. Avoid maxAge on access cookies; see Access token expiry.
Usage
- Direct
- Server-side
- App Router
import { createAuthCookieUtils } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
const {
getAuthCookie,
getAuthCookies,
getAuthTokenOverride,
removeAllCookies,
removeAuthCookies,
removeAuthTokenCookies,
setAuthCookie,
} = createAuthCookieUtils(authConfig, { context });
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { createAuthCookieUtils } = createServerSideAuth(authConfig, {
cacheAdapter,
});
import { createAuthCookieUtils } from "@/lib/auth/server";
const {
getAuthCookie,
getAuthCookies,
getAuthTokenOverride,
removeAllCookies,
removeAuthCookies,
removeAuthTokenCookies,
setAuthCookie,
} = createAuthCookieUtils({ context });
The App Router factory does not return createAuthCookieUtils, instead it
returns the utility functions directly.
import { createAppRouterAuth } from "@krakentech/blueprint-auth/server";
import { cookies, headers } from "next/headers";
import { cache } from "react";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const {
getAuthCookie,
getAuthCookies,
getAuthTokenOverride,
removeAllCookies,
removeAuthCookies,
removeAuthTokenCookies,
setAuthCookie,
} = createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
import {
getAuthCookie,
getAuthCookies,
getAuthTokenOverride,
removeAllCookies,
removeAuthCookies,
removeAuthTokenCookies,
setAuthCookie,
} from "@/lib/auth/server";
Cookies are read-only inside Server Components. setAuthCookie, removeAuthCookies,
removeAuthTokenCookies, and removeAllCookies still run, but if Next.js blocks the cookie
mutation, the write is ignored (logged at debug) instead of throwing. Other errors are still
thrown.
API Handlers
The package exports factories for API Routes and Route Handlers. In the output tables, Data is the
response union for that factory.
| Aspect | API Route | Route Handler |
|---|---|---|
| Export | Default handler export | Named HTTP method export |
| Arguments | NextApiRequest, NextApiResponse | NextRequest |
| Return | Mutates NextApiResponse and resolves to undefined | Returns NextResponse |
| Body | Uses req.body | Reads and parses the request body |
| OAuth query | Uses req.query | Uses URL search parameters |
| Redirect | Calls res.redirect(url) | Returns NextResponse.redirect(url) |
The handler factories set Cache-Control to no-cache, no-store, max-age=0, must-revalidate on
JSON responses. Redirect responses do not receive this header from Blueprint Auth.
createLoginHandler
The login handler authenticates the user with an email address and password. It verifies the returned access token before it sets cookies.
Configuration
- Kraken
- App Routes
- Customization
- i18n
- Validation
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
krakenConfig.authEndpoint | Auth endpoint for verification keys | string | KRAKEN_AUTH_ENDPOINT | ✅ |
krakenConfig.graphqlAuthEndpoint | GraphQL endpoint for auth operations | string | KRAKEN_GRAPHQL_AUTH_ENDPOINT | ✅ |
krakenConfig.xClientIpOverride | Override the client IP sent to Kraken | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
appRoutes.dashboard.pathname | Dashboard pathname | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
| Option | Description | Type | Required |
|---|---|---|---|
i18n.localeCookie | Name of the cookie storing user's locale preference | string | ❌ |
i18n.getLocalizedPathname | Callback to resolve localized pathnames | (options: GetLocalizedPathnameOptions) => string | ❌ |
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
validation.accessTokenIssuers | Exact trusted access token issuers | string[] | KRAKEN_ACCESS_TOKEN_ISSUERS (comma-separated) | ✅ |
validation.allowedRequestOrigins | Trusted origins for CSRF protection (see createAuthConfig) | string[] | ALLOWED_REQUEST_ORIGINS (comma-separated) | ✅ |
validation.validateGraphQLEndpointUrl | Validate the Kraken GraphQL auth endpoint URL | boolean | ❌ |
Output
| Type | Description |
|---|---|
(req: NextApiRequest, res: NextApiResponse) => Promise<undefined> | Handler function for Pages Router |
(req: NextRequest) => Promise<NextResponse<Data>> | Handler function for App Router |
Usage
- Pages Router
- App Router
import { createLoginHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export default createLoginHandler(authConfig);
You may not need a Route Handler for login with the App Router, check out the login
Server Function.
import { createLoginHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export const POST = createLoginHandler(authConfig);
Request
The login handler expects a POST request with a JSON body containing the following fields:
| Field | Description | Type | Required |
|---|---|---|---|
captchaResponse | CAPTCHA response | string | ❌ |
email | User email | string | ✅ |
enableRedirect | Return a redirect response | boolean | ❌ |
nextPage | Redirect pathname or no redirect | string | null | ❌ |
password | User password | string | ✅ |
Response
When enableRedirect is false or omitted, the success response body contains:
| Field | Description | Type |
|---|---|---|
data.redirectUrl | URL to use after login, or null when no URL is selected | string | null |
The error response body contains:
| Field | Description | Type |
|---|---|---|
error.errorCode | Error code | ErrorCode |
error.message | Error message | string |
error.source | Source of the error | "blueprint-auth" |
Status Codes
| Status Code | Condition |
|---|---|
| 200 OK | Login succeeds and enableRedirect is false or omitted |
| 307 Temporary Redirect | Login succeeds and enableRedirect is true |
| 307 Temporary Redirect | Authentication fails and enableRedirect is true. The destination is the request pathname with an error parameter |
| 400 Bad Request | The body or credentials are invalid and the handler returns JSON |
| 401 Unauthorized | Kraken returns an unauthorized error and the handler returns JSON |
| 403 Forbidden | Origin evidence is untrusted or absent, or Content-Type is not JSON |
| 405 Method Not Allowed | The request method is not POST |
| 503 Service Unavailable | Verification keys are not available |
createLogoutHandler
The logout handler removes auth cookies and provides a redirect URL in the response.
For an OAuth session, Blueprint Auth first tries the upstream logout and token revocation requests. It logs an upstream failure and continues to remove local cookies. A local cookie removal failure still fails the logout operation.
Configuration
- App Routes
- Customization
- Kraken
- i18n
- Validation
| Option | Description | Type | Required |
|---|---|---|---|
appRoutes.home.pathname | Default redirect after logout | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
krakenConfig.authEndpoint | Kraken auth endpoint | string | KRAKEN_AUTH_ENDPOINT | ⚠️ Required for OAuth logout |
krakenConfig.oauthClientId | Kraken OAuth client ID | string | KRAKEN_OAUTH_CLIENT_ID | ⚠️ Required for OAuth logout |
krakenConfig.xClientIpOverride | Override the client IP sent to Kraken | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
i18n.localeCookie | Name of the cookie storing user's locale preference | string | ❌ |
i18n.getLocalizedPathname | Callback to resolve localized pathnames | (options: GetLocalizedPathnameOptions) => string | ❌ |
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
validation.allowedRequestOrigins | Trusted origins for CSRF protection (see createAuthConfig) | string[] | ALLOWED_REQUEST_ORIGINS (comma-separated) | ✅ |
Output
| Type | Description |
|---|---|
(req: NextApiRequest, res: NextApiResponse) => Promise<undefined> | Handler function for Pages Router |
(req: NextRequest) => Promise<NextResponse<Data>> | Handler function for App Router |
Usage
- Pages Router
- App Router
import { createLogoutHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export default createLogoutHandler(authConfig);
You may not need a Route Handler for logout with the App Router, check out the logout
Server Function.
import { createLogoutHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export const POST = createLogoutHandler(authConfig);
Request
The logout handler expects a POST request with a JSON body containing the following fields:
| Field | Description | Type | Required |
|---|---|---|---|
enableRedirect | Return a redirect response | boolean | ❌ |
nextPage | Redirect pathname or no redirect | string | null | ❌ |
Response
When enableRedirect is false or omitted, the success response body contains:
| Field | Description | Type |
|---|---|---|
data.redirectUrl | URL to use after logout, or null when no URL is selected | string | null |
The error response body contains:
| Field | Description | Type |
|---|---|---|
error.errorCode | Error code | ErrorCode |
error.message | Error message | string |
error.source | Source of the error | "blueprint-auth" |
Status Codes
| Status Code | Condition |
|---|---|
| 200 OK | Logout succeeds and enableRedirect is false or omitted |
| 307 Temporary Redirect | Successful logout, redirect to home or nextPage (when enableRedirect is true) |
| 400 Bad Request | Invalid request body (validation error) |
| 403 Forbidden | Untrusted Origin / Referer, missing both headers, or non-JSON Content-Type |
| 405 Method Not Allowed | Request method is not POST |
| 500 Internal Server Error | Unknown logout operation error |
createSessionHandler
The session handler selects and verifies one user token. It returns session data from the verified token fields.
Configuration
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
customization.accessTokenRefreshThresholdSeconds | Proactive access token refresh threshold | number | ❌ Defaults to 60 | |
customization.getCookieOptions | Cookie options used when writing a replacement access token | function | ❌ | |
customization.headersToForward | Incoming headers to include in authentication refresh requests | string[] | ❌ | |
customization.setCustomHeaders | Add headers to authentication refresh requests | function | ❌ | |
krakenConfig.authEndpoint | Auth endpoint for verification keys and OAuth refresh | string | KRAKEN_AUTH_ENDPOINT | ✅ |
krakenConfig.graphqlAuthEndpoint | GraphQL endpoint for email and mobile refresh | string | KRAKEN_GRAPHQL_AUTH_ENDPOINT | ❌ Defaults to krakenConfig.graphqlEndpoint |
krakenConfig.oauthClientId | OAuth client ID used for OAuth refresh | string | KRAKEN_OAUTH_CLIENT_ID | ⚠️ Required for OAuth refresh |
krakenConfig.xClientIpOverride | Override the client IP sent during email and mobile refresh | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key used to sign the client IP during email/mobile refresh | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
validation.accessTokenIssuers | Exact trusted access token issuers | string[] | KRAKEN_ACCESS_TOKEN_ISSUERS | ✅ |
Output
| Type | Description |
|---|---|
(req: NextApiRequest, res: NextApiResponse) => Promise<undefined> | Handler for Pages Router |
(req: NextRequest) => Promise<NextResponse<Data>> | Handler for App Router |
Usage
- Pages Router
- App Router
import { createSessionHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export default createSessionHandler(authConfig);
Use the getSession Server Function when you do not need a public session route.
import { createSessionHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export const GET = createSessionHandler(authConfig);
Request
The session handler accepts a GET request.
Response
The success response contains:
| Field | Description | Type |
|---|---|---|
data.authMethod | Method from the verified gty field | AuthMethod | null |
data.authSource | Location of the selected token | AuthSource | null |
data.isAuthenticated | The request has a verified user token | boolean |
data.sub | User ID from the verified sub field | string | null |
The error response contains:
| Field | Description | Type |
|---|---|---|
error.errorCode | Error code | ErrorCode |
error.message | Error message | string |
error.source | Error source | "blueprint-auth" |
Status Codes
| Status Code | Condition |
|---|---|
| 200 OK | The handler returns session state |
| 405 Method Not Allowed | The request method is not GET |
| 500 Internal Server Error | Session resolution fails |
| 503 Service Unavailable | Verification keys or access token refresh services are unavailable |
createGraphQLHandler
The GraphQL handler sends requests to krakenConfig.graphqlEndpoint. It selects and verifies one
user token before it sets the Authorization header.
Configuration
- Kraken
- Customization
- Validation
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
krakenConfig.authEndpoint | Auth endpoint for verification keys | string | KRAKEN_AUTH_ENDPOINT | ✅ |
krakenConfig.graphqlAuthEndpoint | GraphQL endpoint for auth operations | string | KRAKEN_GRAPHQL_AUTH_ENDPOINT | ✅ |
krakenConfig.graphqlEndpoint | Target GraphQL endpoint | string | KRAKEN_GRAPHQL_ENDPOINT | ✅ |
krakenConfig.oauthClientId | OAuth client ID used for OAuth refresh | string | KRAKEN_OAUTH_CLIENT_ID | ⚠️ Required for OAuth refresh |
krakenConfig.xClientIpOverride | Override for the user IP header (for tests) | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
customization.accessTokenRefreshThresholdSeconds | Set the proactive refresh threshold, in seconds, for eligible user access tokens | number | ❌ |
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
customization.getGraphQLErrorLogLevel | Select the log level for a GraphQL error | (context: AuthErrorLogContext) => "debug" | "error" | "info" | "warn" | undefined | ❌ |
customization.headersToForward | Select incoming headers to forward to Kraken | string[] | ❌ |
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
validation.accessTokenIssuers | Exact trusted access token issuers | string[] | KRAKEN_ACCESS_TOKEN_ISSUERS (comma-separated) | ✅ |
validation.allowedRequestOrigins | Trusted origins for CSRF protection (see createAuthConfig) | string[] | ALLOWED_REQUEST_ORIGINS (comma-separated) | ✅ |
validation.preventGraphQLMutations | Prevent GraphQL mutations | (graphQLEndpoint: string) => boolean | ❌ | |
validation.validateGraphQLEndpointUrl | Should validate Kraken GraphQL endpoint URL | boolean | ❌ | |
validation.graphQLRequestValidationOptions | Validate declared Content-Length and query byte length | { maxRequestBodySize?: number; maxQueryLength?: number } | ❌ Defaults: maxRequestBodySize 100 KB (102400 bytes), maxQueryLength 50 KB (51200 bytes) |
maxRequestBodySize checks the declared Content-Length, not the actual body size. Configure a
server or proxy limit if you need a hard cap. See
validateGraphQLRequest for the available limits.
If you omit customization.headersToForward (or pass an empty array), no request headers are
forwarded to Kraken.
The authenticated client still sets Kraken headers such as authorization, x-kraken-client-ip,
and x-kraken-client-ip-authorization. It also sets headers from customization.setCustomHeaders.
This behavior does not depend on the forwarding list.
Output
| Type | Description |
|---|---|
(req: NextApiRequest, res: NextApiResponse) => Promise<undefined> | Handler function for Pages Router |
(req: NextRequest) => Promise<NextResponse<Data>> | Handler function for App Router |
Usage
- Pages Router
- App Router
import { createGraphQLHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export default createGraphQLHandler(authConfig);
You may not need a Route Handler for GraphQL operations with the App Router. Use
getAuth and getGraphQLClient from a Server Component or Server
Action.
import { createGraphQLHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export const POST = createGraphQLHandler(authConfig);
Request
The GraphQL handler expects a POST request with a JSON body containing the following fields:
| Field | Description | Type | Required |
|---|---|---|---|
query | GraphQL query/mutation | string | ✅ |
variables | Variables of the GraphQL query/mutation | object | ❌ |
x-error-policy headerClient-side requests made through useGraphQLClient are proxied through this
handler. The x-error-policy header is set automatically based on the error policy
you configure, whether at the client level or per-request through the
object configuration. You do not need to set this header yourself.
Response
With the "none" or "ignore" error policy, a successful response has this shape:
| Field | Description | Type |
|---|---|---|
data | GraphQL response data | Shape of the query or mutation result |
A handled error response has this shape:
| Field | Description | Type |
|---|---|---|
data | Partial data or null | Shape of the operation result or null |
errors | GraphQL errors | KrakenError[] |
With the "all" error policy, the handler passes through the GraphQL response envelope. It can
contain data, errors, extensions, and headers.
The handler resolves authentication first. Authentication can send a separate token refresh request.
The handler then submits the GraphQL operation once and handles that response according to
errorPolicy.
The GraphQL handler passes errors returned by the GraphQL API endpoint through.
In case an error occurs inside of the GraphQL handler, the error is converted to match the
KrakenError interface, and includes the following fields:
| Field | Description | Type |
|---|---|---|
message | Error message | string |
extensions.errorCode | Error code | string |
extensions.errorDescription | Error description | string |
Status Codes
| Status Code | Condition |
|---|---|
| 200 OK | The handler returns data or a handled GraphQL error |
| 503 Service Unavailable | Verification keys or access token refresh services are unavailable |
createKrakenOAuthHandler
The Kraken OAuth handler authenticates the user using the Kraken OAuth flow. It is meant to be used
in combination with generateKrakenOAuthURI. It gets tokens from Kraken.
It verifies both tokens before it sets cookies. On success, it redirects the user to the dashboard.
On failure, it redirects the user to the login page with an error parameter.
Configuration
- Kraken
- App Routes
- API Routes
- Customization
- i18n
- Validation
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
krakenConfig.authEndpoint | Kraken auth endpoint | string | KRAKEN_AUTH_ENDPOINT | ✅ |
krakenConfig.oauthClientId | Kraken OAuth client ID | string | KRAKEN_OAUTH_CLIENT_ID | ✅ |
krakenConfig.xClientIpOverride | Override the client IP sent to Kraken | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
appRoutes.dashboard.pathname | Dashboard pathname | string | ✅ |
appRoutes.login.pathname | Login pathname | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
apiRoutes.krakenOAuth | Kraken OAuth API endpoint | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
customization.getCookieOptions | Customize cookie options | (cookieName: [CookieName](#cookiename)) => SerializeOptions | undefined | ❌ |
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
| Option | Description | Type | Required |
|---|---|---|---|
i18n.localeCookie | Name of the cookie storing user's locale preference | string | ❌ |
i18n.getLocalizedPathname | Callback to resolve localized pathnames | (options: GetLocalizedPathnameOptions) => string | ❌ |
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
validation.accessTokenIssuers | Exact trusted access token issuers | string[] | KRAKEN_ACCESS_TOKEN_ISSUERS (comma-separated) | ✅ |
Output
| Type | Description |
|---|---|
(req: NextApiRequest, res: NextApiResponse) => Promise<undefined> | Handler function for Pages Router |
(req: NextRequest) => Promise<NextResponse<Data>> | Handler function for App Router |
Usage
- Pages Router
- App Router
import { createKrakenOAuthHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export default createKrakenOAuthHandler(authConfig);
import { createKrakenOAuthHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export const GET = createKrakenOAuthHandler(authConfig);
Request
The Kraken OAuth handler expects a GET request with the following URL search parameters:
| URL search parameter | Description | Type | Required |
|---|---|---|---|
code | Kraken OAuth code | string | ⚠️ Required when error is absent |
error | Standard OAuth error value | string | ❌ |
The Kraken OAuth handler requires a Proof Key for Code Exchange (PKCE)
verifier in the incoming pkceVerifier cookie. generateKrakenOAuthURI creates the verifier and
writes this cookie.
After a successful token exchange, the handler removes pkceVerifier. It then verifies both
returned tokens. The identity token must use the OAuth client ID as its audience. Its issuer must be
the auth token endpoint. The access token must be a verified OAuth token. Both tokens must have the
same sub field.
Response
A GET callback returns a redirect response. The Location header identifies the dashboard after
success. It identifies the login page with an error code after authentication failure.
A request with another method returns the standard JSON error response. It does not redirect or process OAuth tokens.
Status Codes
| Status Code | Condition |
|---|---|
| 307 Temporary Redirect (to Dashboard) | Successful OAuth authentication |
| 307 Temporary Redirect (to Login) | The callback has an OAuth error, required value is missing, token exchange fails, or token verification fails |
| 405 Method Not Allowed | Request method is not GET. The response is JSON and does not redirect |
| 503 Service Unavailable | Verification keys are not available |
createUpdateOrgTokenHandler
The organization token update handler is meant to be used as a Vercel cron job. It fetches a new organization token and stores the value in the configured cache.
Configuration
- Kraken
- Cache
- Encryption
- Customization
- Validation
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
krakenConfig.authEndpoint | Auth endpoint for verification keys | string | KRAKEN_AUTH_ENDPOINT | ✅ |
krakenConfig.graphqlAuthEndpoint | GraphQL endpoint for auth operations | string | KRAKEN_GRAPHQL_AUTH_ENDPOINT | ✅ |
krakenConfig.organizationSecretKey | Kraken organization secret key | string | KRAKEN_ORGANIZATION_KEY | ✅ |
krakenConfig.xClientIpOverride | Override the client IP sent to Kraken | string | ❌ | |
krakenConfig.xClientIpSecretKey | Secret key to sign the user IP address | string | KRAKEN_X_CLIENT_IP_SECRET_KEY | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
cacheAdapter | Shared cache used to store the organization access token | AuthCacheAdapter | ✅ |
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
encryption.key | Encryption secret key | string | AUTH_ENCRYPTION_KEY | ✅ |
Blueprint Auth creates a unique initialization vector for each organization token.
| Option | Description | Type | Required |
|---|---|---|---|
customization.setCustomHeaders | Customize request headers | (headers: Headers, context: [SetCustomHeadersContext](#setcustomheaderscontext)) => void | Promise<void> | ❌ |
| Option | Description | Type | Environment variable | Required |
|---|---|---|---|---|
validation.accessTokenIssuers | Exact trusted access token issuers | string[] | KRAKEN_ACCESS_TOKEN_ISSUERS | ✅ |
validation.validateGraphQLEndpointUrl | Validate the Kraken GraphQL auth endpoint URL | boolean | ❌ |
Set CRON_SECRET in the production environment. Vercel sends its value in the Authorization
header when it invokes the cron job. The handler requires the exact value Bearer <CRON_SECRET>.
A match proves that the caller knows the secret. It does not prove that Vercel sent the request. The
handler returns 401 Unauthorized when the value does not match.
See the Vercel documentation for more information.
Output
| Type | Description |
|---|---|
(req: NextApiRequest, res: NextApiResponse) => Promise<undefined> | Handler function for Pages Router |
(req: NextRequest) => Promise<NextResponse<Data>> | Handler function for App Router |
Usage
- Pages Router
- App Router
import { createUpdateOrgTokenHandler } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "@/lib/auth/cache";
import { authConfig } from "@/lib/auth/config";
export default createUpdateOrgTokenHandler(authConfig, { cacheAdapter });
import { createUpdateOrgTokenHandler } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "@/lib/auth/cache";
import { authConfig } from "@/lib/auth/config";
export const GET = createUpdateOrgTokenHandler(authConfig, { cacheAdapter });
To set up the cron job, create a vercel.json at the root of your project with the following
content:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"crons": [
{
"path": "/api/auth/update-org-token",
"schedule": "*/30 * * * *"
}
]
}
Request
The update organization token handler expects a GET request with the Authorization header set to
Bearer {CRON_SECRET}.
Response
The handler returns this JSON response after a successful update:
{
"data": "Success"
}
Status Codes
| Status Code | Condition |
|---|---|
| 200 OK | Successfully updated organization token |
| 401 Unauthorized | Missing Authorization header or header does not match CRON_SECRET |
| 405 Method Not Allowed | Request method is not GET |
| 500 Internal Server Error | Error updating organization token, cache write failure, or any unknown error |
| 503 Service Unavailable | Verification keys are not available |
Client Functions
If you are using the Next.js App Router, you most likely do not need any of these helpers, use Server Functions instead.
createClientSideAuth
Creates AuthProvider and the hooks depending on it, i.e. useAuth,
useGraphQLClient, useKrakenAuthErrorHandler,
useLogin, useLogout, and useSession.
Configuration
- App Routes
- API Routes
- i18n
| Option | Description | Type | Required |
|---|---|---|---|
appRoutes.dashboard.pathname | Dashboard pathname | string | ✅ |
appRoutes.home.pathname | Home pathname | string | ✅ |
appRoutes.login.pathname | Login pathname | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
apiRoutes.graphql | GraphQL API endpoints | Record<string, string> | ✅ |
apiRoutes.login | Login API endpoint | string | ✅ |
apiRoutes.logout | Logout API endpoint | string | ✅ |
apiRoutes.session | Session API endpoint | string | ✅ |
| Option | Description | Type | Required |
|---|---|---|---|
i18n.localeCookie | Name of the cookie storing user's locale preference | string | ❌ |
i18n.getLocalizedPathname | Callback to resolve localized pathnames | (options: GetLocalizedPathnameOptions) => string | ❌ |
Parameters
| Param | Description | Type | Required |
|---|---|---|---|
defaultTarget | Default GraphQL API endpoint | keyof typeof apiRoutes.graphql | ✅ |
router | Specifies which Next.js router the application uses. | "app-router" | "pages-router" | ✅ |
If your application uses multiple GraphQL endpoints relying on Kraken authentication, you can define
them in the apiRoutes.graphql object.
{
apiRoutes: {
graphql: {
kraken: "/api/graphql/kraken",
custom: "/api/graphql/custom",
}
}
}
The createClientSideAuth factory expects an options object as its second argument with two
properties:
defaultTarget: The default GraphQL endpoint used byuseGraphQLClient. The value must be a key of theapiRoutes.graphqlobject.router: The Next.js router being used. Must be either"pages-router"or"app-router".
Usage
- Pages Router
- App Router
Export the functions returned by createClientSideAuth.
import { createClientSideAuth } from "@krakentech/blueprint-auth/client";
import { authConfig } from "./config";
export const {
AuthProvider,
useAuth,
useGraphQLClient,
useKrakenAuthErrorHandler,
useLogin,
useLogout,
useSession,
} = createClientSideAuth(authConfig, {
defaultTarget: "kraken",
router: "pages-router",
});
Export the functions returned by createClientSideAuth.
"use client";
import { createClientSideAuth } from "@krakentech/blueprint-auth/client";
import { authConfig } from "./config";
export const {
AuthProvider,
useAuth,
useGraphQLClient,
useKrakenAuthErrorHandler,
useLogin,
useLogout,
useSession,
} = createClientSideAuth(authConfig, {
defaultTarget: "kraken",
router: "app-router",
});
The "use client" directive is required to hint Next.js that the module exports a client component,
i.e. AuthProvider.
AuthProvider
Provides configuration to auth hooks.
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
children | Child React nodes | ReactNode | ✅ |
onLoginSuccess | Successful login callback | (defaultRedirect: () => void) => void | Promise<void> | ❌ |
onLoginError | Login error callback | (errorCode: [ErrorCode](#errorcode), defaultRedirect: () => void) => void | Promise<void> | ❌ |
onLogoutSuccess | Successful logout callback | (defaultRedirect: () => void) => void | Promise<void> | ❌ |
onLogoutError | Logout error callback | (errorCode: [ErrorCode](#errorcode), defaultRedirect: () => void) => void | Promise<void> | ❌ |
Usage
- Pages Router
- App Router
In your Next.js _app.tsx file, wrap the page component with AuthProvider, and
optionally define custom handlers.
import type { AppProps } from "next/app";
import { useRouter } from "next/router";
import { useToast } from "@/hooks/useToast";
import { AuthProvider } from "@/lib/auth/client";
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter();
const toast = useToast("auth");
return (
<AuthProvider
// extend default behavior
onLoginSuccess={(defaultRedirect) => {
defaultRedirect();
toast("login.success", { type: "success" });
}}
// override default behavior
onLoginError={(errorCode) => {
toast("login.error", { errorCode, type: "error" });
}}
// optionally extend default behavior
onLogoutSuccess={(defaultRedirect) => {
toast("logout.success", { type: "success" });
if (router.pathname.startsWith("/dashboard")) {
defaultRedirect();
}
}}
>
<Component {...pageProps} />
</AuthProvider>
);
}
Create a Providers Client Component including all your global providers, and render it in your
root layout.tsx.
"use client";
import { QueryClientProvider, QueryClient, isServer } from "@tanstack/react-query";
import { usePathname } from "next/navigation";
import type { PropsWithChildren } from "react";
import { AuthProvider } from "@/lib/auth/client";
import { useToast } from "@/hooks/useToast";
let browserQueryClient: QueryClient | undefined = undefined;
function getQueryClient() {
if (isServer) {
return new QueryClient();
} else {
if (!browserQueryClient) browserQueryClient = new QueryClient();
return browserQueryClient;
}
}
export function Providers({ children }: PropsWithChildren) {
const toast = useToast("auth");
const pathname = usePathname();
const queryClient = getQueryClient();
return (
<QueryClientProvider client={queryClient}>
<AuthProvider
// extend default behavior
onLoginSuccess={(defaultRedirect) => {
toast("login.success", { type: "success" });
defaultRedirect();
}}
// override default behavior
onLoginError={(errorCode) => {
toast("login.error", { errorCode, type: "error" });
}}
// optionally extend default behavior
onLogoutSuccess={(defaultRedirect) => {
toast("logout.success", { type: "success" });
if (pathname?.startsWith("/dashboard")) {
defaultRedirect();
}
}}
>
{children}
</AuthProvider>
</QueryClientProvider>
);
}
import { Providers } from "./providers";
export default function RootLayout({ children }: LayoutProps<"/">) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
useAuth
This hook is used internally by other auth hooks to access the AuthProviderContext state.
This hook is exposed for convenience in advanced use cases, e.g. custom auth hooks. In most cases you should not use it directly.
Configuration
No configuration needed.
Output
| Field | Description | Type | Required |
|---|---|---|---|
apiRoutes.graphql | GraphQL API endpoints | Record<string, string> | ✅ |
apiRoutes.login | Login API endpoint | string | ✅ |
apiRoutes.logout | Logout API endpoint | string | ✅ |
apiRoutes.session | Session API endpoint | string | ✅ |
appRoutes.dashboard.pathname | Dashboard pathname | string | ✅ |
appRoutes.home.pathname | Home pathname | string | ✅ |
appRoutes.login.pathname | Login pathname | string | ✅ |
defaultTarget | Default GraphQL endpoint | string | ✅ |
handlers.onLoginSuccess | Successful login callback | (defaultRedirect: () => void) => void | Promise<void> | ❌ |
handlers.onLoginError | Login error callback | (errorCode: ErrorCode, defaultRedirect: () => void) => void | Promise<void> | ❌ |
handlers.onLogoutSuccess | Successful logout callback | (defaultRedirect: () => void) => void | Promise<void> | ❌ |
handlers.onLogoutError | Logout error callback | (errorCode: ErrorCode, defaultRedirect: () => void) => void | Promise<void> | ❌ |
i18n.getLocalizedPathname | Localized pathname callback | (options: GetLocalizedPathnameOptions) => string | ❌ |
i18n.localeCookie | Locale cookie name | string | ❌ |
Requirements
| Requirement | Notes |
|---|---|
| Context provider | Use inside AuthProvider. |
| Client-side auth | The component must be wrapped with a client-side auth setup using createClientSideAuth. |
Usage
import { useAuth } from "@/lib/auth/client";
function useCustomLogin() {
const { apiRoutes, appRoutes, defaultTarget, handlers } = useAuth();
...
}
useGraphQLClient
Get a preconfigured GraphQL client to perform authenticated requests to the Kraken GraphQL API endpoint, or GraphQL API endpoint relying on Kraken for authentication.
Requirements
| Requirement | Notes |
|---|---|
| API endpoint | Create the GraphQL API endpoint at apiRoutes.graphql using createGraphQLHandler. |
| Context provider | Use inside AuthProvider. |
Configuration
| Parameter | Description | Type | Required |
|---|---|---|---|
target | Target GraphQL endpoint (must be a key of the apiRoutes.graphql object provided to createClientSideAuth) | string | ❌ Defaults to the default target |
errorPolicy | How the client handles GraphQL errors: "none" (default), "ignore", or "all". See Error policy. | "none" | "ignore" | "all" | ❌ Defaults to "none" |
Returns
A BlueprintGraphQLClient<Policy> instance.
Usage
import { useQuery } from "@tanstack/react-query";
import { AccountQuery } from "@/graphql/AccountQuery";
import { useGraphQLClient } from "@/lib/auth/client";
export function useAccount(variables: { accountNumber: string }) {
const graphQLClient = useGraphQLClient();
return useQuery({
queryKey: ["account", variables.accountNumber],
queryFn: () => graphQLClient.request(AccountQuery, variables),
});
}
Use useGraphQLClient({ target: "custom" }) to select another configured target. Use
useGraphQLClient({ errorPolicy: "ignore" }) to return data when a response also contains GraphQL
errors.
useKrakenAuthErrorHandler
The hook provides an error handler to be used with data fetching libraries. If the error is
auth-related the handler redirects the user to the login page with error and nextPage search
parameters.
Requirements
| Requirement | Notes |
|---|---|
| Context provider | Use inside AuthProvider. |
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
onError | Error callback | (error: unknown, defaultRedirect: () => void) => void | Promise<void> | ❌ |
redirectType | Redirect type | "push" | "replace" | ❌ Defaults to "push" |
Providing onError overrides the default redirect behavior of the
useKrakenAuthErrorHandler hook. In case you need to extend the
default behavior, the onError callback is called with the defaultRedirect function.
Output
| Field | Description | Type | Required |
|---|---|---|---|
handleKrakenErrors | Error handler | (error: unknown) => void | Promise<void> | ✅ |
When i18n is configured, this hook redirects to localized login pages based on the user's locale.
Usage
Pass query errors to handleKrakenErrors inside queryFn, then rethrow them so React Query records
the failure:
"use client";
import { useQuery } from "@tanstack/react-query";
import { AccountQuery } from "@/graphql/AccountQuery";
import { useGraphQLClient, useKrakenAuthErrorHandler } from "@/lib/auth/client";
export function useAccount(variables: { accountNumber: string }) {
const graphQLClient = useGraphQLClient();
const { handleKrakenErrors } = useKrakenAuthErrorHandler();
return useQuery({
queryKey: ["account", variables.accountNumber],
queryFn: async () => {
try {
return await graphQLClient.request(AccountQuery, variables);
} catch (error) {
await handleKrakenErrors(error);
throw error;
}
},
retry: false,
});
}
useLogin
The useLogin hook can be used to authenticate the user, and handles redirection for
both success and failure cases.
Learn more about the useLogin hook redirect behavior
Default success redirect
- Redirect to the
nextPageoption if set. - Redirect to the
nextPageURL search parameter if set. - Redirect to the
appRoutes.dashboard.pathnameotherwise.
Default failure redirect
Set the error URL search parameter in the current URL.
Customizing redirects
To replace the default redirects, provide handlers.onLoginSuccess and handlers.onLoginError to
AuthProvider. Each callback must call its supplied defaultRedirect to retain
the default navigation.
The onSuccess and onError callbacks passed to login.mutate or login.mutateAsync supplement
the hook callbacks. They do not replace or suppress the hook's redirects.
If the handlers.onLoginSuccess callback set on the AuthProvider does not call
the defaultRedirect function, the nextPage option and the nextPage URL search parameter have
no effect.
Requirements
| Requirement | Notes |
|---|---|
| API endpoint | Create the login API endpoint at apiRoutes.login using createLoginHandler. |
| Context provider | Use inside AuthProvider. |
| React Query | Use inside of <QueryClientProvider>, see the Pages Router or the App Router example. |
Login API Handler
The useLogin hook expects the login API handler created with
createLoginHandler to be available on the apiRoutes.login endpoint.
QueryClientProvider
The useLogin hook uses React Query's useMutation under the hood. It must be used
inside of <QueryClientProvider>. Check out React Query's
Pages Router example. or
App Router example.
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
nextPage | Redirect pathname | string | null | ❌ |
Output
Returns a UseMutationResult object, see React Query's
useMutation hook documentation.
Usage
import type { FormEvent } from "react";
import { useLogin } from "@/lib/auth/client";
export function LoginForm() {
const login = useLogin();
function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const email = formData.get("email");
const password = formData.get("password");
if (typeof email !== "string" || typeof password !== "string") {
return;
}
login.mutate({ email, password });
}
return (
<form method="POST" onSubmit={handleSubmit}>
<input name="email" type="email" required />
<input name="password" type="password" required />
<button type="submit" disabled={login.isPending}>
Log in
</button>
</form>
);
}
The error code can be read from the error URL search parameter. The UseMutationResult object
returned by the useLogin hook also includes the error response accessible as
login.error. The error code can be extracted from the error response using the
getErrorCode utility function.
Set method="POST" on a form that contains credentials. This prevents the browser from adding
credentials to the URL before hydration. See the
Pages Router login form guide.
useLogout
The useLogout hook can be used to log out the user, and handles redirection for both
success and failure cases.
Learn more about the useLogout hook redirect behavior
Default success redirect
- Redirect to the
nextPageoption if set. - Redirect to
appRoutes.home.pathnameotherwise.
Default failure redirect
Set the error URL search parameter in the current URL.
Customizing redirects
To replace the default redirects, provide handlers.onLogoutSuccess and handlers.onLogoutError to
AuthProvider. Each callback must call its supplied defaultRedirect to retain
the default navigation.
The onSuccess and onError callbacks passed to logout.mutate or logout.mutateAsync supplement
the hook callbacks. They do not replace or suppress the hook's redirects.
If the handlers.onLogoutSuccess callback set on the AuthProvider does not call
the defaultRedirect function, the nextPage option has no effect.
Requirements
| Requirement | Notes |
|---|---|
| API endpoint | Create the logout API endpoint at apiRoutes.logout using createLogoutHandler. |
| Context provider | Use inside AuthProvider. |
| React Query | Use inside of <QueryClientProvider>, see the Pages Router or the App Router example. |
Logout API Handler
The useLogout hook expects the logout API handler created with
createLogoutHandler to be available on the apiRoutes.logout endpoint.
QueryClientProvider
The useLogout hook uses React Query's useMutation under the hood. It must be used inside of
<QueryClientProvider>. Check out React Query's
Pages Router example. or
App Router example.
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
nextPage | Redirect pathname | string | null | ❌ |
Output
| Type | Description |
|---|---|
UseMutationResult | React Query mutation result, see useMutation docs |
Usage
import { useLogout } from "@/lib/auth/client";
export function LogoutButton() {
const logout = useLogout();
return (
<button type="button" disabled={logout.isPending} onClick={() => logout.mutate()}>
Log out
</button>
);
}
The error code can be read from the error URL search parameter. The UseMutationResult object
returned by the useLogout hook also includes the error response accessible as
logout.error. The error code can be extracted from the error response using the
getErrorCode utility function.
useSession
The useSession hook can be used to access information about the current user
session.
Requirements
| Requirement | Notes |
|---|---|
| API endpoint | Create the session API endpoint at apiRoutes.session using createSessionHandler. |
| Context provider | Use inside AuthProvider. |
| React Query | Use inside of <QueryClientProvider>, see the Pages Router or the App Router example. |
Configuration
No configuration needed.
Output
Returns a DefinedUseQueryResult<SessionState, unknown> object.
The SessionState data includes:
| Field | Description | Type |
|---|---|---|
authMethod | Method from the verified token grant | AuthMethod | null |
authSource | Location of the selected token | AuthSource | null |
isAuthenticated | The request has a verified user token | boolean |
sub | User ID from the verified token | string | null |
The initial data has isAuthenticated: false while the first request runs. Check isFetched before
you render a signed-out state. Check isError before you use the session data.
import { useSession } from "@/lib/auth/client";
export function SessionControls() {
const { data: session, error, isError, isFetched } = useSession();
if (!isFetched) {
return <SessionSkeleton />;
}
if (isError) {
return <SessionError error={error} />;
}
return session.isAuthenticated ? <LogoutButton /> : <LoginButton />;
}
redirectToNextPage
The redirectToNextPage function redirects the user to the relative URL
found in the nextPage URL search parameter.
If nextPage is empty or contains an absolute URL, the fallback is used. If nextPage is invalid
and the fallback is not provided, the function has no effect.
Requirements
| Requirement | Notes |
|---|---|
| Pages Router | This function requires a NextRouter instance from the Pages Router. |
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
router | The NextRouter instance | NextRouter | ✅ |
fallback | The fallback URL in case nextPage is empty or invalid | string | ❌ |
redirectType | Navigation method | "push" | "replace" | ❌ Defaults to "replace" |
Output
Returns Promise<boolean> when it starts a navigation. Returns undefined when it has no valid
destination.
Usage
import { useRouter } from "next/router";
import { redirectToNextPage } from "@krakentech/blueprint-auth/client";
const Page = () => {
const router = useRouter();
useEffect(() => {
redirectToNextPage({
router,
fallback: "/dashboard",
});
}, []);
return <p>Redirecting...</p>;
};
Testing
createMockAuthTokenIssuer
Creates a temporary RS256 key pair for server tests. It can create signed access tokens and return the matching JSON Web Key Set (JWKS).
Import it from the testing entry point:
import { createMockAuthTokenIssuer } from "@krakentech/blueprint-auth/testing";
const issuer = await createMockAuthTokenIssuer({
issuer: "https://api.kraken.test/v1/graphql/",
});
const accessToken = await issuer.createAccessToken({
authMethod: "email",
subject: "user-123",
});
const jwks = issuer.getJwks();
| Method | Description |
|---|---|
createAccessToken(options) | Create a signed access token for email, OAuth, scoped, masquerade, or organization auth |
getJwks() | Return the public keys that verify the created tokens |
The helper keeps the private key in memory. Use it only in server test code. Add the test issuer to
validation.accessTokenIssuers. Serve getJwks() from the JWKS URL for the test auth endpoint.
Utils
validateGraphQLRequest
Validate the Content-Length header and GraphQL query size. The GraphQL handler calls this utility
automatically.
function validateGraphQLRequest(
context: ApiRouteHandlerContext | RouteHandlerContext,
query: string,
options?: {
maxQueryLength?: number;
maxRequestBodySize?: number;
},
): Promise<void>;
maxRequestBodySize: maximum declaredContent-Length, defaulting to 102400 bytes. This is not a hard limit on the actual request body.maxQueryLength: maximum query size in UTF-8 bytes, defaulting to 51200 bytes.
Import from @krakentech/blueprint-auth/server.
convertIterableToRecord
Converts an Iterable (like an Iterator or generator) to a Record object.
function convertIterableToRecord<
T extends {
entries(): Iterable<readonly [string, string]>;
},
>(iterable: T): Record<string, string | string[]>;
Configuration
| Parameter | Description | Type | Required |
|---|---|---|---|
iterable | The iterable to convert | T extends { entries(): Iterable<readonly [string, string]>} | ✅ |
Output
| Type | Description |
|---|---|
Record<string, string | string[]> | A record object created from the iterable |
Usage
const iterable = new Map([
["key1", "value1"],
["key2", "value2"],
]);
const record = convertIterableToRecord(iterable);
// { key1: "value1", key2: "value2" }
convertRecordToIterable
Converts a Record object back to an Iterable.
function convertRecordToIterable<
Entry,
Target extends { append(key: string, value: string): void },
>(record: Record<string, Entry>, target: Target): Target;
Configuration
| Parameter | Description | Type | Required |
|---|---|---|---|
record | The record to convert | Record<string, Entry> | ✅ |
target | The target iterable to append to | Target extends { append(key: string, value: string): void } | ✅ |
Output
| Type | Description |
|---|---|
Target | The target iterable with appended entries |
Usage
const record = { key1: "value1", key2: "value2" };
const iterable = convertRecordToIterable(record, new URLSearchParams());
// URLSearchParams { "key1" => "value1", "key2" => "value2" }
getErrorCode
Get an error code from a Blueprint Auth response or the first Kraken GraphQL error. Returns null
for unrecognized errors. For an AuthError instance, read error.errorCode directly.
Configuration
Expect an error of type unknown.
Output
| Type | Condition |
|---|---|
ErrorCode | Error code found |
null | No error code found |
Usage
import { AuthError } from "@krakentech/blueprint-auth";
import { getErrorCode } from "@krakentech/blueprint-auth/utils";
import { AccountQuery } from "@/graphql/AccountQuery";
import { getAuth, getGraphQLClient } from "@/lib/auth/server";
import { reportGraphQLError, reportUnexpectedError } from "@/lib/error/reporting";
async function getAccount(variables: { accountNumber: string }) {
try {
const auth = await getAuth.user();
if (!auth) throw new Error("Authentication required.");
const graphQLClient = getGraphQLClient.user({ auth });
const { account } = await graphQLClient.request(AccountQuery, variables);
return account;
} catch (error) {
const errorCode = error instanceof AuthError ? error.errorCode : getErrorCode(error);
if (errorCode) {
return reportGraphQLError(error, { errorCode });
}
return reportUnexpectedError(error);
}
}
getErrorType
Get extensions.errorType from a Kraken error. The function uses extensions.errorClass as a
fallback.
function getErrorType(error: KrakenError): KrakenErrorType | undefined;
Import this function from @krakentech/blueprint-auth.
getKrakenErrorDetails
Normalize a Kraken error into a KrakenErrorDetails object.
function getKrakenErrorDetails(error: KrakenError): KrakenErrorDetails;
Import this function from @krakentech/blueprint-auth.
isKrakenErrorResponse
Check whether a value has a Kraken GraphQL error response.
function isKrakenErrorResponse(value: unknown): value is KrakenErrorResponse;
Import this function from @krakentech/blueprint-auth.
isMappedKrakenErrorCode
Check whether a string is a value in krakenErrorTypeToCodeMap.
function isMappedKrakenErrorCode(errorCode: string): errorCode is MappedKrakenErrorCode;
Import this function from @krakentech/blueprint-auth.
isUnauthenticatedError
Check whether an error code indicates that the local user session can no longer authenticate
requests. The function accepts ErrorCode | null and narrows a matching value to ErrorCode.
GraphQL clients return authentication failures to the application. Use this helper for an optional policy that ends the local session.
Import it from @krakentech/blueprint-auth/utils.
isBlueprintAuthErrorCode
Check if an error code is a valid BlueprintAuthErrorCode.
Configuration
Expect an error code of type string.
Output
| Type | Description |
|---|---|
errorCode is BlueprintAuthErrorCode | Narrows a valid Blueprint Auth error code |
Usage
import { getTranslations } from "next-intl/server";
import { AuthError, isMappedKrakenErrorCode } from "@krakentech/blueprint-auth";
import { getErrorCode, isBlueprintAuthErrorCode } from "@krakentech/blueprint-auth/utils";
async function getErrorMessage(error: unknown) {
const t = await getTranslations("getErrorMessage");
const errorCode = error instanceof AuthError ? error.errorCode : getErrorCode(error);
if (errorCode) {
if (isBlueprintAuthErrorCode(errorCode)) {
return t(`blueprint-auth.${errorCode}`);
}
if (isMappedKrakenErrorCode(errorCode)) {
return t(`kraken.${errorCode}`);
}
}
return t("unknown");
}
signJwt
Signs a JWT payload with a shared secret.
function signJwt(payload: JWTPayload, secret: string, options?: SignJwtOptions): Promise<string>;
| Option | Default | Description |
|---|---|---|
algorithm | HS256 | HMAC signing algorithm |
expiresIn | 5m | Absolute expiry time or duration from signing |
issuedAt | true | Include the current time, omit the claim with false, or set an absolute time or duration from now |
signJwt throws an AuthMissingPropertiesError when secret is empty.
Usage
import { signJwt } from "@krakentech/blueprint-auth/utils";
const token = await signJwt({ ip: clientIp }, secret);
setNextPageSearchParam
This function sets the nextPage URL search parameter. This is the URL search parameter that we are
setting in the authMiddleware function when we redirect the user to the login page.
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
nextPage | Redirect page pathname or URL | string | URL | ✅ |
url | URL on which to set the nextPage parameter | URL | ✅ |
Output
Returns void.
Usage
import { setNextPageSearchParam } from "@krakentech/blueprint-auth/utils";
const url = new URL("https://example.com/login");
setNextPageSearchParam({
nextPage: "/profile/settings?tab=update-password",
url,
});
// url.href → https://example.com/login?nextPage=%2Fprofile%2Fsettings%3Ftab%3Dupdate-password
If the nextPage URL includes search parameters, they are included in the encoded nextPage URL
search parameter along with the URL pathname.
setNextPageSearchParam removes existing nextPage and error parameters from the destination
URL.
setKrakenAuthTokenOverrideHeader
Manually set the Kraken auth token override header.
Configuration
| Option | Description | Type | Required |
|---|---|---|---|
headers | Headers object | Headers | ✅ |
token | Override token value | string | ✅ |
Output
| Type | Description |
|---|---|
void | No return value |
Usage
"use server";
import { setKrakenAuthTokenOverrideHeader } from "@krakentech/blueprint-auth/utils";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
import { getAuth, getGraphQLClient } from "@/lib/auth/server";
import { CheckoutQuoteInput, CheckoutQuote } from "@/mutations/checkout-quote";
import {
handleRequestError,
handleSubmissionError,
parseSubmission,
type FormState,
} from "@/utils/form-actions";
export async function checkoutAction(token: string, _formState: FormState, formData: FormData) {
const submission = parseSubmission(formData, CheckoutQuoteInput);
if (!submission.success) {
return handleSubmissionError(submission);
}
const requestHeaders = new Headers(await headers());
setKrakenAuthTokenOverrideHeader({ headers: requestHeaders, token });
try {
const auth = await getAuth.viewer();
const graphQLClient = getGraphQLClient.viewer({ auth });
await graphQLClient.request(CheckoutQuote, submission.data, requestHeaders);
} catch (error) {
return handleRequestError(error, submission);
}
redirect("/subscribe/confirmation");
}
Interfaces
BlueprintGraphQLClient<Policy>
The BlueprintGraphQLClient<Policy> interface provides a GraphQL client with resolved
authentication headers and a selected error policy. Each operation sends one GraphQL request.
getGraphQLClient and useGraphQLClient return this
interface.
Policy extends ErrorPolicy and defaults to "none". It is inferred from the
errorPolicy argument passed when creating the client. The value of Policy determines the return
type of .request():
"none"or"ignore"→Promise<T>(data only)"all"→Promise<GraphQLClientResponse<T>>(full response withdata,errors,extensions, andheaders)
Error policy
The client supports an optional error policy that controls how GraphQL errors in responses are handled:
| Policy | Behavior |
|---|---|
"none" | (default) GraphQL errors cause the request to throw. |
"ignore" | GraphQL errors are ignored; response data is returned even when the response contains errors. |
"all" | Response includes both data and errors (rawRequest-style), so the caller can handle errors explicitly. |
The error policy is set when creating the client. See getGraphQLClient or
useGraphQLClient for details.
const auth = await getAuth.user({ context });
if (!auth) throw new Error("Authentication required.");
// Client-level error policy: affects all requests from this client.
const graphQLClient = getGraphQLClient.user({
auth,
errorPolicy: "all",
});
const { data, errors } = await graphQLClient.request(MyQuery);
// Return type is GraphQLClientResponse<T> because errorPolicy is "all"
You can also override the error policy on individual requests using the object configuration style. See the Per-request Override tab in the Usage section below.
request<T, V>(document, ...args)
Execute a GraphQL query or mutation with automatic authentication.
Parameters
- Positional Arguments
- Object Configuration
Pass up to three separate arguments to the request method.
| Parameter | Type | Description | Required |
|---|---|---|---|
document | RequestDocument | TypedDocumentNode | TypedDocumentString | GraphQL operation document | ✅ |
variables | V | GraphQL variables. Inferred from the document type; required if the query defines variables. | Conditional |
requestHeaders | HeadersInit | Request-level headers | ❌ |
const { account } = await graphQLClient.request(
AccountQuery,
{ accountNumber: "A-12345678" },
{ "x-custom-header": "my-value" },
);
Pass a single object to supply a per-request error policy or an AbortSignal. Cancellation requires
the "none" or "ignore" error policy.
| Parameter | Type | Description | Required |
|---|---|---|---|
document | RequestDocument | TypedDocumentNode | TypedDocumentString | GraphQL operation document | ✅ |
variables | V | GraphQL variables. Inferred from the document type; required if the query defines variables. | Conditional |
requestHeaders | HeadersInit | Request-level headers | ❌ |
signal | AbortSignal | null | Cancellation signal; ignored when the effective policy is "all" | ❌ |
errorPolicy | ErrorPolicy | Override the client-level error policy for this request | ❌ |
const abortController = new AbortController();
const { account } = await graphQLClient.request({
document: AccountQuery,
variables: { accountNumber: "A-12345678" },
requestHeaders: { "x-custom-header": "my-value" },
errorPolicy: "none",
signal: abortController.signal,
});
// later, if needed:
abortController.abort();
Output
| Type | Description |
|---|---|
Promise<T> | Returned when Policy is "none" or "ignore". Contains the GraphQL response data directly. |
Promise<GraphQLClientResponse<T>> | Returned when Policy is "all". Contains the full response object with data, errors, extensions, and headers. |
Throws
| Error type | Condition |
|---|---|
| Kraken authentication error | Kraken rejects the selected access token |
AuthError with BlueprintAuthErrorCode.Forbidden | A mutation runs while preventGraphQLMutations returns true |
| Kraken API error | A GraphQL operation fails with error policy "none" |
Usage
- Basic Usage
- Error Policy: "all"
- Per-request Error Policy
- Custom Headers
- Request Cancellation
- Concurrent Requests
Execute GraphQL queries and mutations with automatic authentication:
import { getAuth, getGraphQLClient } from "@/lib/auth/server";
import { graphql } from "@/gql-tada";
const AccountQuery = graphql(`
query Account($accountNumber: String!) {
account(accountNumber: $accountNumber) {
number
balance
status
}
}
`);
export async function getServerSideProps(context) {
const auth = await getAuth.user({ context });
if (!auth) throw new Error("Authentication required.");
const graphQLClient = getGraphQLClient.user({ auth });
// graphQLClient is BlueprintGraphQLClient<"none"> (default)
// request() returns Promise<T>
const { account } = await graphQLClient.request(AccountQuery, {
accountNumber: "A-12345678",
});
return {
props: { account },
};
}
When using errorPolicy: "all", the return type includes the full response envelope:
import { getAuth, getGraphQLClient } from "@/lib/auth/server";
import { graphql } from "@/gql-tada";
const AccountQuery = graphql(`
query Account($accountNumber: String!) {
account(accountNumber: $accountNumber) {
number
balance
}
}
`);
const auth = await getAuth.user({ context });
if (!auth) throw new Error("Authentication required.");
const graphQLClient = getGraphQLClient.user({
auth,
errorPolicy: "all",
});
// graphQLClient is BlueprintGraphQLClient<"all">
// request() returns Promise<GraphQLClientResponse<T>>
const { data, errors } = await graphQLClient.request(AccountQuery, {
accountNumber: "A-12345678",
});
if (errors) {
console.warn("Partial data returned with errors:", errors);
}
console.log(data.account.balance);
Override the client-level error policy for a specific request using the object configuration style.
Client-side (with useGraphQLClient):
const graphQLClient = useGraphQLClient();
// graphQLClient is BlueprintGraphQLClient<"none">
// Override to "all" for this specific request
const { data, errors } = await graphQLClient.request({
document: AccountQuery,
variables: { accountNumber: "A-12345678" },
errorPolicy: "all",
});
// Return type is GraphQLClientResponse<T> because of the "all" override
Server-side (with getGraphQLClient.user):
const auth = await getAuth.user({ context });
if (!auth) throw new Error("Authentication required.");
const graphQLClient = getGraphQLClient.user({ auth });
// graphQLClient is BlueprintGraphQLClient<"none">
// Override to "all" for this specific request
const { data, errors } = await graphQLClient.request({
document: AccountQuery,
variables: { accountNumber: "A-12345678" },
errorPolicy: "all",
});
// Return type is GraphQLClientResponse<T> because of the "all" override
The per-request errorPolicy override is only available when using the object configuration style.
Use request({ document, errorPolicy }) instead of request(document, variables, headers).
Client-level headers (via config)
Set headers that apply to all requests made with any client instance:
import { createAuthConfig } from "@krakentech/blueprint-auth";
const authConfig = createAuthConfig({
// ... other config
customization: {
setCustomHeaders: (headers) => {
headers.set("x-client-version", "1.0.0");
headers.set("x-tracking-id", generateTrackingId());
},
},
});
All requests made with any client instance will include these headers.
Request-level headers (via request method)
Set headers for a specific request only:
const { account } = await graphQLClient.request(
AccountQuery,
{ accountNumber: "A-12345678" },
{ "x-request-id": requestId }, // Only for this specific request
);
The auth context supplies the token, client IP, and resolved headers. Request-level headers are
limited to customization.headersToForward. Reserved auth headers are removed. Use
x-kraken-auth-token-override for an explicit operation token override.
Use AbortController to cancel requests. Cancellation is not supported with errorPolicy: "all":
import { graphql } from "@/gql-tada";
const LongRunningQuery = graphql(`
query LongRunning {
complexData {
# ... expensive query
}
}
`);
const abortController = new AbortController();
// start the request
const requestPromise = graphQLClient.request({
document: LongRunningQuery,
errorPolicy: "none",
signal: abortController.signal,
});
// cancel after 5 seconds
setTimeout(() => {
abortController.abort();
}, 5000);
try {
const data = await requestPromise;
} catch (error) {
if (error instanceof Error && error.name === "AbortError") {
console.log("Request was cancelled");
}
}
The signal parameter is only available when using the object configuration style. Use
request({ document, signal }) instead of request(document, variables, headers).
Run concurrent requests with standard Promise APIs. Each operation sends one GraphQL request:
import { getAuth, getGraphQLClient } from "@/lib/auth/server";
import { graphql } from "@/gql-tada";
const UserQuery = graphql(`
query User {
viewer {
email
fullName
}
}
`);
const AccountQuery = graphql(`
query Account($accountNumber: String!) {
account(accountNumber: $accountNumber) {
number
balance
}
}
`);
export async function getServerSideProps(context) {
const auth = await getAuth.user({ context });
if (!auth) throw new Error("Authentication required.");
const graphQLClient = getGraphQLClient.user({ auth });
// These three requests run concurrently with the resolved auth context.
const [user, account1, account2] = await Promise.all([
graphQLClient.request(UserQuery),
graphQLClient.request(AccountQuery, { accountNumber: "A-12345678" }),
graphQLClient.request(AccountQuery, { accountNumber: "A-87654321" }),
]);
return {
props: { user, account1, account2 },
};
}
Server-side request behavior
A server GraphQL client submits each operation once. Resolve auth before you create the client.
Authentication resolution can send a separate token refresh request. Handle authentication errors in
application code. Use isUnauthenticatedError only if the application must end the local session.
AuthError
AuthError represents an authentication failure created by Blueprint Auth. Public functions can
also expose platform, network, validation, provider, and framework errors. For example, Next.js
navigation functions throw redirect errors.
Constructor
new AuthError(
message: string,
options?: {
cause?: unknown;
code?: ErrorCode;
logLevel?: "debug" | "error" | "info" | "warn" | AuthErrorLogLevelResolver;
},
)
Parameters:
| Parameter | Type | Description | Required |
|---|---|---|---|
message | string | Error message | ✅ |
options.cause | unknown | Underlying cause | ❌ |
options.code | ErrorCode | Blueprint Auth or Kraken error code | ❌ |
options.logLevel | "debug" | "error" | "info" | "warn" | AuthErrorLogLevelResolver | Log level or resolver | ❌ |
Properties
| Property | Type | Description |
|---|---|---|
message | string | Error message |
errorCode | ErrorCode | Blueprint Auth or Kraken error code |
cause | unknown | Original cause, if present |
source | "blueprint-auth" | Package that created the error |
Usage
import { AuthError, BlueprintAuthErrorCode } from "@krakentech/blueprint-auth";
import { login } from "@/lib/auth/server";
// Throw an AuthError.
throw new AuthError("Invalid credentials", {
code: BlueprintAuthErrorCode.BadRequest,
});
// Catch and handle AuthError.
try {
await login({ context, input: { email, password } });
} catch (error) {
if (error instanceof AuthError) {
console.error("Auth error:", error.errorCode, error.message);
if (error.errorCode === BlueprintAuthErrorCode.TokenAccessInvalid) {
// handle expired token
}
}
}
Error Code Utilities
For an AuthError instance, first check error instanceof AuthError, then read
error.errorCode directly.
getErrorCode(error)extracts codes from supported Blueprint Auth and Kraken response shapes, not fromAuthErrorinstances.isBlueprintAuthErrorCode(code)checks whether the extracted code is specific to Blueprint.
Types
Public type inventory
Import public types from these entry points.
| Entry point | Public types |
|---|---|
@krakentech/blueprint-auth | ApiRouteHandlerContext, ApiRoutes, AppRoutes, AuthCacheAdapter, AuthCacheValue, AuthConfig, AuthContext, AuthErrorLogContext, AuthErrorLogLevelResolver, AuthHandlers, AuthMethod, AuthScope, AuthSource, AuthUserConfig, BlueprintAuthErrorCode, BlueprintGraphQLClient, CookieMap, CookieName, CreateAuthCacheProfilesConfig, ErrorCode, ErrorPolicy, KrakenError, KrakenErrorDetails, KrakenErrorResponse, KrakenErrorType, MappedKrakenErrorCode, MappedKrakenErrorType, MiddlewareContext, RouteHandlerContext, ServerActionContext, ServerComponentContext, ServerSideContext, ServerSidePropsContext, SessionState, StaticPropsContext |
@krakentech/blueprint-auth/cache/global-config | CreateGlobalConfigCacheAdapterOptions |
@krakentech/blueprint-auth/client | CreateClientSideAuthOptions |
@krakentech/blueprint-auth/middleware | AuthMiddlewareConfig, CreateAuthCookieUtilsConfig, CreateAuthCookieUtilsParams |
@krakentech/blueprint-auth/server | AppRouterLoginParams, AppRouterLogoutParams, AppRouterPrefetchSessionParams, AppRouterRedirectToLoginParams, AuthContext, AuthSource, CacheFunction, CreateAppRouterAuthParams, CreateAuthCookieUtilsConfig, CreateAuthCookieUtilsParams, CreateAuthServerFunctionsConfig, CreateServerSideAuthParams, CreateUpdateOrgTokenHandlerParams, GenerateKrakenOAuthURIConfig, GenerateKrakenOAuthUriParams, GetRequestPathnameParams, GetSessionParams, LoginConfig, LoginParams, LogoutParams, PrefetchSessionParams, RedirectToLoginConfig, RedirectToLoginParams, ValidateGraphQLRequestOptions, getAuth.OrgConfig, getAuth.OrgParams, getAuth.UserConfig, getAuth.UserParams, getAuth.ViewerConfig, getAuth.ViewerParams, getGraphQLClient.Config, getGraphQLClient.OrgParams, getGraphQLClient.UserParams, getGraphQLClient.ViewerParams |
@krakentech/blueprint-auth/testing | CreateMockAuthTokenIssuerOptions, MockAccessTokenOptions, MockAuthMethod, MockAuthTokenIssuer |
@krakentech/blueprint-auth/utils | No type exports |
AuthCacheAdapter
The shared server cache interface for authentication data:
interface AuthCacheAdapter {
get(key: string, options?: { bypassCache?: boolean }): Promise<AuthCacheValue | undefined>;
set(key: string, value: AuthCacheValue): Promise<void>;
}
See the custom adapter contract for the required read, fresh-read, missing-value, write, and error behavior.
AuthCacheValue
The JSON-compatible values that an AuthCacheAdapter can store:
type AuthCacheValue =
boolean | number | string | null | AuthCacheValue[] | { [key: string]: AuthCacheValue };
AuthContext
A namespace for the server-only values returned by getAuth.*.
| Type | Required fields | Meaning |
|---|---|---|
AuthContext.Viewer | authScope: "user", session | User or Unauthenticated |
AuthContext.User | accessToken, authScope: "user", authSource, session | Local user credentials |
AuthContext.Unauthenticated | authScope: "user", session: null | No usable local user credentials |
AuthContext.Org | accessToken, authScope: "organization", authSource | Organization credentials |
AuthContext.Base | None | Optional clientIp and headers shared by each context |
AuthContext.Viewer is a discriminated union. Check session before using an access token:
const auth = await getAuth.viewer();
if (auth.session) {
// auth is AuthContext.User here.
getGraphQLClient.user({ auth });
}
Any context can contain resolved request headers. Treat the whole context as a credential. Keep it on the server and out of Client Components, browser code, logs, and public props.
AuthSource
Identifies where Blueprint Auth found the verified token:
type AuthSource = "web" | "mobile-web-view" | "override";
| Value | Meaning |
|---|---|
"web" | Web token for email, OAuth, scoped, masquerade, or organization auth |
"mobile-web-view" | Mobile web view token |
"override" | A request token override |
AuthSource differs from AuthMethod. AuthMethod identifies the verified grant. A request
override is not refreshed with other request credentials.
AuthMethod
Identifies the user method from the verified access token grant:
type AuthMethod = "email" | "oauth" | "scoped" | "masquerade";
JWT gty field | AuthMethod |
|---|---|
EMAIL-AND-PASSWORD | "email" |
OPENID-CONNECT | "oauth" |
PRE-SIGNED-TOKEN | "scoped" |
MASQUERADE | "masquerade" |
AuthMethod does not identify where Blueprint Auth found the token. Use AuthSource
for that information. SessionState.authMethod is null when the request has no verified user.
See Session management for a session lifecycle overview.
Usage
import { getSession } from "@/lib/auth/server";
export async function SessionSummary({ context }: SessionSummaryProps) {
const session = await getSession({ context });
return (
<>
{session.authMethod === "masquerade" && <MasqueradeBanner />}
{session.authSource === "mobile-web-view" && <UpdateAppLink />}
{session.isAuthenticated ? <LogoutButton /> : <LoginButton />}
</>
);
}
AuthScope
Represents the scope of authentication for GraphQL operations.
type AuthScope = "user" | "organization";
Values
| Value | Description |
|---|---|
"user" | Authenticates operations performed on behalf of a user. |
"organization" | Authenticates operations performed with organization credentials. |
Usage
The AuthScope type is used in the customization.setCustomHeaders callback and
internally by GraphQL client functions.
const authConfig = createAuthConfig({
customization: {
setCustomHeaders(headers, { authScope }) {
if (authScope === "organization") {
headers.set("X-Custom-Org-Header", "value");
}
},
},
});
BlueprintAuthErrorCode
Blueprint-specific error codes for authentication operations. All error codes follow the pattern
BP-AUTH-XXXX.
const BlueprintAuthErrorCode = {
/* General Errors */
Unknown: "BP-AUTH-0000",
BadRequest: "BP-AUTH-0001",
AuthenticationRequired: "BP-AUTH-0002",
ResponseNotFound: "BP-AUTH-0003",
Forbidden: "BP-AUTH-0004",
CookieWrite: "BP-AUTH-0005",
/* Token Errors */
TokenUnknown: "BP-AUTH-0100",
TokenAccessInvalid: "BP-AUTH-0101",
TokenNotRefreshable: "BP-AUTH-0102",
TokenOrganizationUnavailable: "BP-AUTH-0103",
TokenVerificationInvalid: "BP-AUTH-0104",
TokenVerificationUnavailable: "BP-AUTH-0105",
TokenGrantUnsupported: "BP-AUTH-0106",
TokenRefreshUnavailable: "BP-AUTH-0107",
/* API Handler Errors */
ApiHandlerUnknown: "BP-AUTH-0200",
ApiHandlerRequestNotFound: "BP-AUTH-0201",
ApiHandlerInvalidParameters: "BP-AUTH-0202",
ApiHandlerMethodNotAllowed: "BP-AUTH-0203",
/* Server Function Errors */
ServerFunctionUnknown: "BP-AUTH-0300",
ServerFunctionUnsupportedExecutionContext: "BP-AUTH-0301",
/* Operation Errors */
OperationUnknown: "BP-AUTH-0400",
OperationLoginUnknown: "BP-AUTH-0410",
OperationOAuthUnknown: "BP-AUTH-0420",
OperationLogoutUnknown: "BP-AUTH-0430",
OperationLogoutUpstreamUnavailable: "BP-AUTH-0431",
OperationSessionUnknown: "BP-AUTH-0440",
OperationGraphQLUnknown: "BP-AUTH-0450",
/* Cache Errors */
CacheUnknown: "BP-AUTH-0500",
CacheRead: "BP-AUTH-0501",
CacheReadFresh: "BP-AUTH-0502",
CacheWrite: "BP-AUTH-0503",
/* Encryption Errors */
EncryptionUnknown: "BP-AUTH-0600",
/* Validation Errors */
ValidationUnknown: "BP-AUTH-0700",
ValidationApiUrl: "BP-AUTH-0701",
ValidationMissingProperties: "BP-AUTH-0702",
ValidationInvalidProperties: "BP-AUTH-0703",
ValidationRequestBodyTooLarge: "BP-AUTH-0704",
ValidationQueryStringTooLong: "BP-AUTH-0705",
/* Client Errors */
ClientUnknown: "BP-AUTH-0800",
ClientHookUsedOutsideOfProvider: "BP-AUTH-0802",
} as const;
type BlueprintAuthErrorCode = (typeof BlueprintAuthErrorCode)[keyof typeof BlueprintAuthErrorCode];
Error Codes
| Code | Constant | Category | Description |
|---|---|---|---|
BP-AUTH-0000 | Unknown | General | Unknown error |
BP-AUTH-0001 | BadRequest | General | Bad request |
BP-AUTH-0002 | AuthenticationRequired | General | Protected resource requires authentication |
BP-AUTH-0003 | ResponseNotFound | General | Response not found |
BP-AUTH-0004 | Forbidden | General | Forbidden operation |
BP-AUTH-0005 | CookieWrite | General | Auth cookie write failed |
BP-AUTH-0100 | TokenUnknown | Token | Unknown token error |
BP-AUTH-0101 | TokenAccessInvalid | Token | Invalid or expired access token |
BP-AUTH-0102 | TokenNotRefreshable | Token | Token cannot be refreshed |
BP-AUTH-0103 | TokenOrganizationUnavailable | Token | Organization authentication is unavailable |
BP-AUTH-0104 | TokenVerificationInvalid | Token | Token verification failed |
BP-AUTH-0105 | TokenVerificationUnavailable | Token | Verification keys are not available |
BP-AUTH-0106 | TokenGrantUnsupported | Token | Access token grant is not supported |
BP-AUTH-0107 | TokenRefreshUnavailable | Token | Access token refresh is temporarily unavailable |
BP-AUTH-0200 | ApiHandlerUnknown | API Handler | Unknown API handler error |
BP-AUTH-0201 | ApiHandlerRequestNotFound | API Handler | API request not found |
BP-AUTH-0202 | ApiHandlerInvalidParameters | API Handler | Invalid parameters provided to API handler |
BP-AUTH-0203 | ApiHandlerMethodNotAllowed | API Handler | HTTP method not allowed |
BP-AUTH-0300 | ServerFunctionUnknown | Server Function | Unknown server function error |
BP-AUTH-0301 | ServerFunctionUnsupportedExecutionContext | Server Function | Server function called in unsupported context |
BP-AUTH-0400 | OperationUnknown | Operation | Unknown operation error |
BP-AUTH-0410 | OperationLoginUnknown | Operation | Unknown login operation error |
BP-AUTH-0420 | OperationOAuthUnknown | Operation | Unknown OAuth operation error |
BP-AUTH-0430 | OperationLogoutUnknown | Operation | Unknown logout operation error |
BP-AUTH-0431 | OperationLogoutUpstreamUnavailable | Operation | Upstream OAuth logout request failed |
BP-AUTH-0440 | OperationSessionUnknown | Operation | Unknown session operation error |
BP-AUTH-0450 | OperationGraphQLUnknown | Operation | Unknown GraphQL operation error |
BP-AUTH-0500 | CacheUnknown | Cache | Unknown cache error |
BP-AUTH-0501 | CacheRead | Cache | Cached read failed |
BP-AUTH-0502 | CacheReadFresh | Cache | Fresh read failed |
BP-AUTH-0503 | CacheWrite | Cache | Cache write failed |
BP-AUTH-0600 | EncryptionUnknown | Encryption | Unknown encryption error |
BP-AUTH-0700 | ValidationUnknown | Validation | Unknown validation error |
BP-AUTH-0701 | ValidationApiUrl | Validation | Invalid API URL |
BP-AUTH-0702 | ValidationMissingProperties | Validation | Missing required properties |
BP-AUTH-0703 | ValidationInvalidProperties | Validation | Invalid property values |
BP-AUTH-0704 | ValidationRequestBodyTooLarge | Validation | Declared Content-Length exceeds maxRequestBodySize |
BP-AUTH-0705 | ValidationQueryStringTooLong | Validation | GraphQL query string exceeds maxQueryLength |
BP-AUTH-0800 | ClientUnknown | Client | Unknown client-side error |
BP-AUTH-0802 | ClientHookUsedOutsideOfProvider | Client | React hook used outside of AuthProvider |
Usage
import { AuthError, BlueprintAuthErrorCode } from "@krakentech/blueprint-auth";
import { login } from "@/lib/auth/server";
try {
await login({ context, input: { email, password } });
} catch (error) {
if (!(error instanceof AuthError)) throw error;
const errorCode = error.errorCode;
if (errorCode === BlueprintAuthErrorCode.TokenAccessInvalid) {
// handle invalid token
} else if (errorCode === BlueprintAuthErrorCode.ValidationMissingProperties) {
// handle validation error
} else {
throw error;
}
}
CookieMap
Contains the managed cookie names and values that are present on the request.
type CookieMap = Map<CookieName, string>;
Usage
const { getAuthCookies } = createAuthCookieUtils({ context });
const cookies = await getAuthCookies();
const accessToken = cookies.get("accessToken");
const hasAccessToken = cookies.has("accessToken");
Use verified SessionState data to read identity or authMethod. Do not infer
them from cookie presence.
CookieName
Valid authentication cookie names used throughout the package.
type CookieName =
| "accessToken"
| "MWAuthToken"
| "MWRefreshToken"
| "oAuthIdToken"
| "pkceVerifier"
| "refreshToken";
Usage
This type is used by createAuthCookieUtils functions to ensure type-safe
cookie operations. See the AUTH_COOKIE constant for the actual cookie name values.
const { setAuthCookie } = createAuthCookieUtils({ context });
await setAuthCookie({
name: "accessToken", // type-safe: must be a valid CookieName
value: token,
expires: new Date(Date.now() + 3600000),
});
ErrorCode
Union type of all possible error codes from Blueprint Auth and the Kraken API.
type ErrorCode = BlueprintAuthErrorCode | MappedKrakenErrorCode;
This type combines:
BlueprintAuthErrorCoderepresents auth errors specific to Blueprint, such asBP-AUTH-0001.MappedKrakenErrorCoderepresents Kraken API errors mapped by@krakentech/blueprint-auth.
ErrorPolicy
Controls how GraphQL errors in responses are handled by
BlueprintGraphQLClient. The error policy also determines the return
type of the .request() method through type-level inference.
type ErrorPolicy = "none" | "ignore" | "all";
Values
| Value | Return type of .request() | Behavior |
|---|---|---|
"none" | Promise<T> | (default) GraphQL errors cause the request to throw. |
"ignore" | Promise<T> | GraphQL errors are ignored; response data is returned even when the response contains errors. |
"all" | Promise<GraphQLClientResponse<T>> | Response includes both data and errors (rawRequest-style), so the caller can handle errors explicitly. |
Usage
import { getAuth, getGraphQLClient } from "@/lib/auth/server";
const auth = await getAuth.user({ context });
if (!auth) throw new Error("Authentication required.");
// Default: errorPolicy is "none", request() returns Promise<T>.
const client = getGraphQLClient.user({ auth });
const { account } = await client.request(AccountQuery, { accountNumber });
// With "all": request() returns Promise<GraphQLClientResponse<T>>.
const allClient = getGraphQLClient.user({ auth, errorPolicy: "all" });
const { data, errors } = await allClient.request(AccountQuery, {
accountNumber,
});
SessionState
Represents the current user session state. See getSession and
useSession for full documentation.
type SessionState = {
authMethod: AuthMethod | null;
authSource: AuthSource | null;
isAuthenticated: boolean;
sub: string | null;
};
Identity and authMethod come from verified access token fields. See
Session management for a
session lifecycle overview.
SetCustomHeadersContext
Context passed as the second argument to customization.setCustomHeaders.
interface SetCustomHeadersContext {
authScope: AuthScope;
clientIp: string | undefined;
}
authScope is the AuthScope of the request to Kraken.
For clientIp, Blueprint Auth prefers krakenConfig.xClientIpOverride, then the first address in
x-forwarded-for. The value is undefined when no client IP is available.
Usage
Use clientIp to send the client IP to a service that reads a different header from the one Kraken
reads.
import { signJwt } from "@krakentech/blueprint-auth/utils";
const authConfig = createAuthConfig({
customization: {
async setCustomHeaders(headers, { clientIp }) {
const secret = process.env.DOWNSTREAM_IP_SECRET;
if (!clientIp || !secret) return;
headers.set("x-downstream-client-ip", await signJwt({ ip: clientIp }, secret));
},
},
});
Constants
createAuthCacheProfiles
Creates the auth profile for Next.js Cache Components. Pass the same server-only auth config that
runtime auth uses.
| Profile | stale | revalidate | expire |
|---|---|---|---|
auth | 300 seconds | 3600 - accessTokenRefreshThresholdSeconds seconds | 3600 seconds |
The default refresh threshold is 60 seconds. The default revalidate value is therefore 3540
seconds.
import { createAuthCacheProfiles } from "@krakentech/blueprint-auth";
import type { NextConfig } from "next";
import { authConfig } from "./src/lib/auth/config";
const nextConfig: NextConfig = {
cacheComponents: true,
cacheLife: { ...createAuthCacheProfiles(authConfig) },
};
export default nextConfig;
Use this profile only for cache timing. Check access at the request boundary because a stale entry can remain after an access token expires or permissions change.
See the Cache Components guide for request boundaries and server-only handling.
AUTH_COOKIE
| Constant | Value | Description |
|---|---|---|
AUTH_COOKIE.accessToken | "accessToken" | Web access token cookie |
AUTH_COOKIE.MWAuthToken | "MWAuthToken" | Mobile web view access token cookie |
AUTH_COOKIE.MWRefreshToken | "MWRefreshToken" | Mobile web view refresh token cookie |
AUTH_COOKIE.oAuthIdToken | "oAuthIdToken" | OAuth identity token cookie |
AUTH_COOKIE.pkceVerifier | "pkceVerifier" | OAuth PKCE verifier cookie |
AUTH_COOKIE.refreshToken | "refreshToken" | Web refresh token cookie |
HTTP Headers
| Constant | Value | Description |
|---|---|---|
krakenAuthTokenOverrideHeader | "x-kraken-auth-token-override" | Header for token override in scoped requests |
xClientIpHeader | "x-kraken-client-ip" | Header containing the client IP address |
xClientIpAuthorizationHeader | "x-kraken-client-ip-authorization" | Header with signed client IP for rate-limiting prevention |
xErrorPolicyHeader | "x-error-policy" | Internal transport header for error policy ("none", "ignore", "all"). Set automatically by the client returned from useGraphQLClient based on the configured error policy. |
xErrorPolicyHeader directlyIn normal application code, the client from useGraphQLClient handles this
header for you automatically. Server-side requests do not go through the handler, so this header is
not relevant there. The xErrorPolicyHeader constant is exported for tests and advanced use cases
where you need to make requests through the GraphQL handler without using the hook.
Kraken error codes
krakenErrorTypeToCodeMap maps authentication error names to Kraken error codes. Import it from
@krakentech/blueprint-auth.
| Key | Value |
|---|---|
AUTH_HEADER_NOT_PROVIDED | "KT-CT-1112" |
EXPIRED_JWT_SIGNATURE | "KT-CT-1124" |
EXPIRED_REFRESH_TOKEN | "KT-CT-1134" |
FAILED_AUTHENTICATION | "KT-CT-1142" |
INCORRECT_CREDENTIALS | "KT-CT-1138" |
INTERNAL_ERROR | "KT-CT-7899" |
INVALID_AUTH_HEADER | "KT-CT-1143" |
INVALID_REFRESH_TOKEN | "KT-CT-1135" |
ISSUER_VERIFICATION_FAILED | "KT-CT-1127" |
SIGNATURE_VERIFICATION_FAILED | "KT-CT-1126" |
TOKEN_EXPIRED | "KT-CT-1120" |
TOO_MANY_REQUESTS | "KT-CT-1199" |
UNAUTHORIZED | "KT-CT-1111" |
UNAUTHORIZED_REFRESH_TOKEN | "KT-CT-1130" |
URL Parameters
| Constant | Value | Description |
|---|---|---|
sessionQueryKey | ["session"] | Query key for session queries |
ignoredQueryParams | ["nextPage", "error"] | Query parameters to remove from redirect destinations |
nextPageParam | "nextPage" | URL parameter for the destination after an auth operation |