Migrating authentication to v44
Overview​
To upgrade from version 43, configure token verification. If you use organization auth, also configure a shared cache adapter. Replace the scoped GraphQL client functions. Update legacy config, cookies, and test tokens.
Version 44 also refreshes eligible user access tokens before expiry. Each submitted GraphQL operation sends one request to the GraphQL endpoint. Authentication resolution can send a separate token refresh request first.
Complete the following steps before you deploy the new version.
Migration Steps​
Step 1: Update the package​
pnpm update @krakentech/blueprint-auth@^44
If you use the supplied Vercel Global Config adapter, replace its legacy peer dependency:
pnpm remove @vercel/edge-config
pnpm add @vercel/global-config
Step 2: Remove old auth configuration​
Remove encryption.iv and edgeConfig from the auth configuration:
export const authConfig = createAuthConfig({
- edgeConfig: {
- authToken: process.env.VERCEL_AUTH_TOKEN,
- envVar: process.env.EDGE_CONFIG,
- teamId: process.env.VERCEL_TEAM_ID,
- },
encryption: {
key: process.env.AUTH_ENCRYPTION_KEY,
- iv: process.env.AUTH_ENCRYPTION_IV,
},
});
Keep AUTH_ENCRYPTION_KEY. Version 44 still uses it to encrypt organization
tokens.
Keep AUTH_ENCRYPTION_IV in the deployment environment while version 43 is
running. Remove it after all active deployments use version 44.
If you set validation.allowedRequestOrigins, check every value. Each value
must be an exact HTTP or HTTPS origin. Remove paths, queries, fragments, and
credentials.
validation: {
allowedRequestOrigins: [
- "https://example.com/account",
+ "https://example.com",
],
},
Step 3: Configure token verification​
Version 44 verifies every JSON Web Token (JWT) before it creates a session. Add the Kraken authentication endpoint and every access token issuer:
KRAKEN_AUTH_ENDPOINT="https://auth.xxxx-kraken.systems/"
KRAKEN_ACCESS_TOKEN_ISSUERS="https://api.xxxx-kraken.systems/v1/graphql/,https://auth.xxxx-kraken.systems/token/,https://support.xxxx-kraken.systems"
An issuer is the iss field in an access token. Use the exact values for your
Kraken environment. Matching is case-sensitive. Paths and trailing slashes are
significant.
Add these three issuer values:
- For OAuth, add
token/to the exact Kraken auth endpoint. For example,https://auth.xxxx-kraken.systems/useshttps://auth.xxxx-kraken.systems/token/. - For scoped and email auth, use the exact Kraken GraphQL endpoint URL, including
its trailing slash. For example,
https://api.xxxx-kraken.systems/v1/graphql/. - For masquerade, use the exact Kraken support site URL without a trailing
slash. For example,
https://support.xxxx-kraken.systems.
The authentication endpoint must use HTTPS. For local development, HTTP is
accepted only for localhost, 127.0.0.1, and [::1].
You can set issuers in code instead of using the environment variable:
import { createAuthConfig } from "@krakentech/blueprint-auth";
export const authConfig = createAuthConfig({
validation: {
accessTokenIssuers: [
"https://api.xxxx-kraken.systems/v1/graphql/",
"https://auth.xxxx-kraken.systems/token/",
"https://support.xxxx-kraken.systems",
],
},
// Keep the rest of your configuration.
});
Step 4: Create a server cache adapter​
This step is required only for organization auth. User and viewer auth, sessions, login, logout, and OAuth do not require an adapter.
For organization auth, create one shared adapter in a module that browser code cannot import. This guide uses the supplied Vercel Global Config adapter.
- App Router
- Pages Router
import "server-only";
import { createGlobalConfigCacheAdapter } from "@krakentech/blueprint-auth/cache/global-config";
export const cacheAdapter = createGlobalConfigCacheAdapter();
import { createGlobalConfigCacheAdapter } from "@krakentech/blueprint-auth/cache/global-config";
export const cacheAdapter = createGlobalConfigCacheAdapter();
Pages Router does not support the server-only marker. Import this module only
from getServerSideProps, API Routes, and other server modules.
The supplied adapter prefers GLOBAL_CONFIG. Existing deployments can keep
EDGE_CONFIG. New configurations should use GLOBAL_CONFIG. Keep
VERCEL_AUTH_TOKEN and VERCEL_TEAM_ID in the deployment environment.
You can provide a different AuthCacheAdapter. Follow the
custom adapter contract
when you implement one. bypassCache is a fresh-read hint for adapters that
have an additional cache layer. An adapter can ignore it when every read already
reaches its backing store.
For local development and isolated tests, use the memory adapter:
import { createMemoryCacheAdapter } from "@krakentech/blueprint-auth/cache/memory";
export const cacheAdapter = createMemoryCacheAdapter();
Each call creates an isolated 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.
Step 5: Pass the adapter to organization auth​
Pass the adapter when you create server auth functions for organization auth.
For user-only setup, use createServerSideAuth(authConfig) or
createAppRouterAuth(authConfig, { cache, cookies, headers }). Omit the adapter
imports and properties in the examples below. The App Router dependencies
cache, cookies, and headers remain required.
Calling a factory's getAuth.org without an adapter fails with
AuthMissingPropertiesError for cacheAdapter.
For organization auth:
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const serverAuth = createServerSideAuth(authConfig, { cacheAdapter });
Also pass { cacheAdapter } to createUpdateOrgTokenHandler and direct
getAuth.org calls. Middleware and standalone user login, session, GraphQL, and
OAuth handlers do not use the adapter.
createSessionHandler now receives authConfig as its argument:
import { createSessionHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
export default createSessionHandler(authConfig);
Step 6: Replace the combined GraphQL client functions​
Version 44 removes getUserScopedGraphQLClient and
getOrganizationScopedGraphQLClient. Resolve auth first. Then create a client
for the same scope.
Use viewer for optional user auth. Use user when a user is required. Use
org for organization operations.
- Direct
- Server-side
- App Router
import { BlueprintAuthErrorCode } from "@krakentech/blueprint-auth";
import {
getAuth,
getGraphQLClient,
redirectToLogin,
} from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
const auth = await getAuth.user(authConfig, { context });
if (!auth) {
return redirectToLogin(authConfig, {
context,
errorCode: BlueprintAuthErrorCode.AuthenticationRequired,
});
}
const client = getGraphQLClient.user(authConfig, { auth });
import { createServerSideAuth } from "@krakentech/blueprint-auth/server";
import { cacheAdapter } from "./cache";
import { authConfig } from "./config";
export const { getAuth, getGraphQLClient, redirectToLogin } =
createServerSideAuth(authConfig, { cacheAdapter });
import { BlueprintAuthErrorCode } from "@krakentech/blueprint-auth";
import { getAuth, getGraphQLClient, redirectToLogin } from "@/lib/auth/server";
const auth = await getAuth.user({ context });
if (!auth) {
return redirectToLogin({
context,
errorCode: BlueprintAuthErrorCode.AuthenticationRequired,
});
}
const client = getGraphQLClient.user({ auth });
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, redirectToLogin } =
createAppRouterAuth(authConfig, {
cache,
cacheAdapter,
cookies,
headers,
});
If your Next.js 16.3 application enables Partial Prefetching, follow the Partial Prefetching setup.
import { BlueprintAuthErrorCode } from "@krakentech/blueprint-auth";
import { getAuth, getGraphQLClient, redirectToLogin } from "@/lib/auth/server";
const auth = await getAuth.user();
if (!auth) {
return redirectToLogin({
errorCode: BlueprintAuthErrorCode.AuthenticationRequired,
});
}
const client = getGraphQLClient.user({ auth });
Replace GetUserScopedGraphQLClientConfig with getAuth.UserConfig and
getGraphQLClient.Config. Replace GetOrganizationScopedGraphQLClientConfig
with getAuth.OrgConfig and getGraphQLClient.Config.
Replace GetUserScopedGraphQLClientParams with getAuth.UserParams and
getGraphQLClient.UserParams. Replace
GetOrganizationScopedGraphQLClientParams with getAuth.OrgParams and
getGraphQLClient.OrgParams.
Each submitted GraphQL operation now sends one request to the GraphQL endpoint. Authentication resolution can send a separate token refresh request first. The client applies the selected error policy to the operation response.
Kraken can reject a verified token after revocation. Use
isUnauthenticatedError
only if the application must end the local session after this failure.
Step 7: Review proactive token refresh​
Version 44 refreshes eligible user access tokens before expiry. The default threshold is 60 seconds. Read Session management for the eligibility rules and refresh failure policy.
Set a different threshold only when the application needs it:
import { createAuthConfig } from "@krakentech/blueprint-auth";
export const authConfig = createAuthConfig({
customization: {
accessTokenRefreshThresholdSeconds: 90,
},
});
Use a whole number from 1 through 3599. Blueprint Auth refreshes when the
remaining whole seconds are less than or equal to this value.
Blueprint Auth uses reactive refresh for missing or expired access tokens. If
Kraken rejects an expired, invalid, or unauthorized refresh token, Blueprint
Auth ends the local session. Review monitoring and custom error handling for
TokenRefreshUnavailable.
Remove customization.isAuthTokenExpired. Blueprint Auth now uses the verified
access token expiry.
Step 8: Update session and cookie code​
Remove code that reads or writes these legacy cookies:
authProvidersubscopedTokenmasqueradeToken
Read identity and authMethod from SessionState or AuthContext. Remove calls
to getActiveAuthMethod. Use getSession, getAuth.viewer, or getAuth.user
instead. Scoped and masquerade access tokens now use accessToken.
Add authSource to session fixtures and exhaustive session handling. Its value
is "web", "mobile-web-view", "override", or null. Replace checks for
authMethod === "mobile-web-view" with
authSource === "mobile-web-view".
Read Session management for the new session lifecycle.
Step 9: Replace unsigned test tokens​
Local auth servers and tests must issue signed tokens. They must also serve the matching public key from the configured JSON Web Key Set (JWKS) endpoint.
Use createMockAuthTokenIssuer for isolated tests:
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();
Serve jwks from .well-known/jwks.json at the test authentication endpoint.
Add the test issuer to KRAKEN_ACCESS_TOKEN_ISSUERS. Keep private keys in
server-only test modules.
OAuth mocks must also return a signed identity token. Set its issuer to the test
auth endpoint plus token/. Set its audience to the test OAuth client ID. Use
the same user ID in the identity token and access token. Include its public key
in the served JWKS.
Keep existing refresh token strings. Do not sign refresh tokens as JWTs.
Step 10: Update error handling​
Replace renamed cache error properties. Their string codes do not change.
| Before | After |
|---|---|
EdgeConfigUnknown | CacheUnknown |
EdgeConfigFetch | CacheRead |
EdgeConfigFetchUpdated | CacheReadFresh |
EdgeConfigUpdate | CacheWrite |
Add the new errors where the application maps or translates auth errors:
| Error | Code |
|---|---|
AuthenticationRequired | BP-AUTH-0002 |
CookieWrite | BP-AUTH-0005 |
TokenOrganizationUnavailable | BP-AUTH-0103 |
TokenVerificationInvalid | BP-AUTH-0104 |
TokenVerificationUnavailable | BP-AUTH-0105 |
TokenGrantUnsupported | BP-AUTH-0106 |
TokenRefreshUnavailable | BP-AUTH-0107 |
createSessionHandler and createGraphQLHandler return
503 Service Unavailable when verification keys or the access token refresh
service is unavailable. Middleware returns 503 Service Unavailable only when
verification keys are unavailable. It propagates reactive refresh errors,
including TokenRefreshUnavailable.
Step 11: Complete the deployment​
Deploy version 44 with AUTH_ENCRYPTION_IV still present. Test email, OAuth,
scoped, masquerade, mobile, and organization auth flows that the application
uses.
Version 44 uses a new key for stored organization tokens. It creates the new value automatically. Do not move or delete the version 43 value.
After all version 43 deployments stop, remove AUTH_ENCRYPTION_IV from the
deployment environment.
Cache Components are optional. Call
createAuthCacheProfiles(authConfig) if you use this Next.js feature. The
factory aligns the profile with the configured refresh threshold.
Follow the Cache Components guide for setup instructions.