Skip to main content

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:

lib/auth/config.ts
 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:

.env.local
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/ uses https://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:

lib/auth/config.ts
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.

lib/auth/cache.ts
import "server-only";

import { createGlobalConfigCacheAdapter } from "@krakentech/blueprint-auth/cache/global-config";

export const cacheAdapter = createGlobalConfigCacheAdapter();

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:

lib/auth/cache.ts
import { createMemoryCacheAdapter } from "@krakentech/blueprint-auth/cache/memory";

export const cacheAdapter = createMemoryCacheAdapter();
Not for cloud production

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:

lib/auth/server.ts
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:

pages/api/auth/session.ts
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.

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 });

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:

lib/auth/config.ts
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.

Remove code that reads or writes these legacy cookies:

  • authProvider
  • sub
  • scopedToken
  • masqueradeToken

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.

BeforeAfter
EdgeConfigUnknownCacheUnknown
EdgeConfigFetchCacheRead
EdgeConfigFetchUpdatedCacheReadFresh
EdgeConfigUpdateCacheWrite

Add the new errors where the application maps or translates auth errors:

ErrorCode
AuthenticationRequiredBP-AUTH-0002
CookieWriteBP-AUTH-0005
TokenOrganizationUnavailableBP-AUTH-0103
TokenVerificationInvalidBP-AUTH-0104
TokenVerificationUnavailableBP-AUTH-0105
TokenGrantUnsupportedBP-AUTH-0106
TokenRefreshUnavailableBP-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.

Optional Cache Components support

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.