Skip to main content

Migrating to v40

This guide will help you migrate @krakentech/blueprint-auth to version 40, which introduces App Router support and a unified configuration system.

Overview

Version 40 of @krakentech/blueprint-auth eliminates configuration duplication by introducing a single source of truth for authentication. Instead of repeating the same settings across middleware, API routes, and client code, you now define your authentication configuration once in a central authConfig object and import it wherever needed.

This becomes possible because all user-facing functions now expect a subset of a single unified interface. Previous versions came close to this design, but some functions had slightly different configuration requirements that prevented using a single shared config object. Now that these interfaces have been aligned, you can pass the same config everywhere.

This architectural shift means you maintain a single source of truth instead of duplicating configuration across multiple files. When you need to update authentication behavior, you make the change in one place rather than hunting through your codebase to ensure all instances stay in sync.

The new implementation brings full App Router support through automatic context detection, meaning the same utilities work seamlessly whether you're using the Pages Router or the App Router. All handlers have been converted to factory functions that accept your config as a parameter, creating a consistent API surface across the entire package. You'll also get improved error handling with structured error codes and messages that guide you toward solutions, as well as better TypeScript inference.

Full API Reference

For complete details on all functions, hooks, and configuration options mentioned in this guide, see the API Reference.

Help us improve this guide

If you identify a breaking change we've missed, please reach out so we can add it to this page. If you run into any issues during migration, don't hesitate to reach out to the team for support.

Migration Steps

We'll work from the inside out: first create the centralized config, then wire it up to your runtime components (middleware, API handlers, client), update any custom code that references old APIs, and finally verify everything works.

Step 1: Update packages

The @krakentech/blueprint-auth and @krakentech/blueprint-api packages must be upgraded together.

pnpm update @krakentech/blueprint-auth@^40 @krakentech/blueprint-api@^4
Other packages

If your project relies on one of the other packages listing @krakentech/blueprint-api as a peer-dependency, you must update them as well:

PackageCommand
@krakentech/blueprint-utilspnpm update @krakentech/blueprint-utils@^55
Package version requirements

If you try to upgrade to @krakentech/blueprint-api@4.0.0 or @krakentech/blueprint-auth@40.0.0 or @krakentech/blueprint-utils@55.0.0 (without prefixing the version with ^ or ~) you will get a warning about a faulty release. Please skip these versions and upgrade directly to the latest version instead.

Step 2: Configuration

Create a centralized config that you'll reuse everywhere. See the createAuthConfig API reference for all available configuration options.

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

export const authConfig = createAuthConfig({
apiRoutes: {
graphql: { kraken: "/api/graphql" },
login: "/api/auth/login",
logout: "/api/auth/logout",
session: "/api/auth/session",
},
appRoutes: {
dashboard: { pathname: "/dashboard" },
login: { pathname: "/login" },
},
krakenConfig: {
graphqlEndpoint: process.env.KRAKEN_GRAPHQL_ENDPOINT,
},
// Optional: customize behavior
customization: {
getCookieOptions: (cookieName) => {
if (cookieName === "accessToken") {
return { maxAge: 3600 };
}
return undefined; // use defaults
},
},
});
Router configuration required for client-side auth

The router option is required if you're using client-side authentication. However, it is not part of authConfig. Instead, it's passed as the second argument to createClientSideAuth (see Step 5 below).

The router option must be set to either "pages-router" or "app-router" depending on your Next.js setup. This tells the auth package which routing strategy to use for client-side redirects.

If you're only using server-side functions (middleware, API handlers, getServerSideProps, etc.), you don't need to specify a router.

Why this helps

Instead of repeating your authentication configuration across multiple files, you now maintain everything in one place. When you need to update your auth setup, you change it here and the update automatically applies everywhere you've imported authConfig.

Migrating existing config

If you're migrating from a previous version, review the config-related breaking changes below before creating your authConfig. This ensures you start with a valid configuration.

ChangeWhat to do
Customization options
  • getCookieOptionscustomization.getCookieOptions
  • setCustomHeaderscustomization.setCustomHeaders
Validation options
  • shouldValidateUrlvalidation.validateGraphQLEndpointUrl
Route extractors
  • getPreSignedKeygetAnonParams
  • getUserIdAndMasqueradeTokengetMasqueradeParams
Custom headers signature
  • (headers) => void(headers, authScope) => void
Cookie options return
  • Omit<HttpContext, "req" | "res">SerializeOptions | undefined

See the Breaking Changes Reference section for detailed examples of each migration.

Now that you have your centralized config, the next step is to use it in your middleware where authentication checks happen first.

Step 3: Middleware

Replace the middleware with the new createAuthMiddleware factory function.

middleware.ts
// Before
import { authMiddleware } from "@krakentech/blueprint-auth/middleware";
import type { NextRequest, NextResponse } from "next/server";

export async function middleware(req: NextRequest) {
const res = NextResponse.next();
return await authMiddleware({
appRoutes: {
dashboard: { pathname: "/dashboard" },
login: { pathname: "/login" },
},
krakenConfig: {
graphqlEndpoint: process.env.KRAKEN_GRAPHQL_ENDPOINT,
},
req,
res,
});
}

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

export const middleware = createAuthMiddleware(authConfig);
Matcher configuration

The matcher export defines which routes the middleware protects. If your existing middleware already has a working matcher, you can keep it as-is. This step only changes how you create the middleware function itself.

With middleware protecting your routes, let's update the API handlers that actually perform authentication operations.

Step 4: API handlers

Replace each handler with a one-liner factory call. See the API reference for details: createLoginHandler, createLogoutHandler, createSessionHandler, createGraphQLHandler, createKrakenOAuthHandler, createUpdateOrgTokenHandler.

pages/api/auth/login.ts
// Before
import { loginHandler } from "@krakentech/blueprint-auth/server";
import type { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
await loginHandler({
krakenConfig: {
/* ... */
},
req,
res,
// ... more config
});
}

// After
import { createLoginHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";

export default createLoginHandler(authConfig);

Your server-side auth is now set up. Time to wire up the client-side code that your components will use.

Step 5: Client-side auth

The client-side auth setup has several important changes. Your authConfig now includes appRoutes field, the AuthProvider no longer takes appRoutes as a prop, and the auth hooks have updated signatures.

createClientSideAuth

The function now takes your centralized authConfig as the first parameter, and a client-only config object as the second parameter. The client-only config includes defaultTarget and router. Your centralized authConfig must include appRoutes (dashboard and login pathnames, previously passed to AuthProvider). See the createClientSideAuth API reference for details.

lib/auth/client.ts
// Before
import { createClientSideAuth } from "@krakentech/blueprint-auth/client";

export const {
AuthProvider,
useAuth,
useLogin,
useLogout,
useSession,
useGraphQLClient,
useKrakenAuthErrorHandler,
} = createClientSideAuth({
apiRoutes: {
graphql: { kraken: "/api/graphql" },
login: "/api/auth/login",
logout: "/api/auth/logout",
session: "/api/auth/session",
},
defaultTarget: "kraken",
});

// After
import { createClientSideAuth } from "@krakentech/blueprint-auth/client";
import { authConfig } from "@/lib/auth/config";

export const {
AuthProvider,
useAuth,
useLogin,
useLogout,
useSession,
useGraphQLClient,
useKrakenAuthErrorHandler,
} = createClientSideAuth(authConfig, {
defaultTarget: "kraken",
router: "pages-router",
});

AuthProvider

The appRoutes prop is removed since routes are now in your authConfig. Handlers are now passed as individual props (onLoginSuccess, onLoginError, onLogoutSuccess, onLogoutError) instead of a single handlers object. Handler signatures have changed: all handlers now receive a defaultRedirect callback function, onLoginError receives an ErrorCode string instead of a KrakenError[] array, and onLogout splits into separate onLogoutSuccess and onLogoutError handlers for better error handling. See the AuthProvider API reference for details.

pages/_app.tsx
// Before
<AuthProvider
appRoutes={{
dashboard: { pathname: "/dashboard" },
login: { pathname: "/login" },
}}
handlers={{
onLoginSuccess: () => {
// custom success logic
},
onLoginError: (errors) => {
// custom error logic
},
onLogout: () => {
// custom logout logic
},
}}
>
{children}
</AuthProvider>

// After
<AuthProvider
onLoginSuccess={(defaultRedirect) => {
// custom success logic, optionally call defaultRedirect()
}}
onLoginError={(errorCode, defaultRedirect) => {
// custom error logic, optionally call defaultRedirect()
}}
onLogoutSuccess={(defaultRedirect) => {
// custom logout success logic
}}
onLogoutError={(errorCode, defaultRedirect) => {
// custom logout error logic
}}
>
{children}
</AuthProvider>

Hooks

If you're using auth hooks with options, their signatures have changed.

useLogin

The shouldRedirectToNextPage boolean flag is replaced by nextPage. Set it to null to prevent redirect, or provide a path to redirect to a specific page. See the useLogin API reference for details.

// Before
const login = useLogin({
shouldRedirectToNextPage: false,
});

// After
const login = useLogin({
nextPage: null,
});
useSession

The return type of the useSession hook has changed. The SessionState type now includes an authMethod field and removes several boolean flags. See the useSession API reference for details.

// Before
const { data: session } = useSession();

if (session.isMasquerading) {
return <MasqueradeBanner />;
}

if (session.isScopedSession) {
return <PaymentDetailsCard />;
}

if (session.isMobileWebView) {
return <UpdateAppLink />;
}

// After
const { data: session } = useSession();

if (session.authMethod === "masquerade") {
return <MasqueradeBanner />;
}

if (session.authMethod === "scoped") {
return <PaymentDetailsCard />;
}

if (session.authMethod === "mobile-web-view") {
return <UpdateAppLink />;
}
useLogout

The hook now accepts an options object. Use nextPage to control the redirect destination, or set it to null to prevent redirect. See the useLogout API reference for details.

// Before
const logout = useLogout();

// After
const logout = useLogout({
nextPage: "/goodbye",
});
useKrakenAuthErrorHandler

The hook now takes an options object instead of a single function. The onError callback receives a defaultRedirect function as its second parameter, and you can specify redirectType ("push" or "replace"). The getAuthErrorCode function is no longer returned from the hook; import getErrorCode directly from the main package instead. See the useKrakenAuthErrorHandler API reference for details.

// Before
const { getAuthErrorCode, handleKrakenErrors } = useKrakenAuthErrorHandler(
(error) => {
// custom error handling
},
);
const errorCode = getAuthErrorCode(error);

// After
import { getErrorCode } from "@krakentech/blueprint-auth/utils";

const { handleKrakenErrors } = useKrakenAuthErrorHandler({
onError: (error, defaultRedirect) => {
// custom error handling
},
redirectType: "replace",
});
const errorCode = getErrorCode(error);

The core migration is complete. Now let's update any remaining server-side code.

Step 6: Server-side auth

Server-side authentication has several important changes. All relate to making the API more consistent and enabling App Router support.

Context parameter change

Server-side functions now accept a context parameter as part of their options object instead of separate req and res parameters. This makes the API more versatile by allowing server functions to adapt to different execution environments, from traditional API routes to newer patterns like Server Components and Server Actions.

Execution environment compatibility

Not all server functions work in every Next.js execution environment. For example, some utilities require request/response objects and won't work in Server Components. See the Execution Environment guide in the API reference for details on which functions work where.

// Before
import { getUserScopedGraphQLClient } from "@krakentech/blueprint-auth/server";
import type { GetServerSidePropsContext } from "next";

export async function getServerSideProps({
req,
res,
}: GetServerSidePropsContext) {
const client = getUserScopedGraphQLClient({
krakenConfig: {
/* ... */
},
req,
res,
});
}

// After
import { getUserScopedGraphQLClient } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
import type { GetServerSidePropsContext } from "next";

export async function getServerSideProps(context: GetServerSidePropsContext) {
const client = getUserScopedGraphQLClient(authConfig, { context });
}

This applies to all server-side utilities including getUserScopedGraphQLClient, getOrganizationScopedGraphQLClient, getSession, login, logout, and more.

Function renaming

Several server-side utilities have been renamed for clarity.

Renamed to getSession.

// Before
import { getSessionData } from "@krakentech/blueprint-auth/server";
import type { GetServerSidePropsContext } from "next";

export async function getServerSideProps({
req,
res,
}: GetServerSidePropsContext) {
const session = await getSessionData({
krakenConfig: {
/* ... */
},
req,
res,
});
}

// After
import { getSession } from "@krakentech/blueprint-auth/server";
import type { GetServerSidePropsContext } from "next";

export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession({ context });
}

getSession

The return type of the getSession server function has changed. The SessionState type now includes an authMethod field and removes several boolean flags. See the getSession API reference for details.

// Before
import { getSession } from "@krakentech/blueprint-auth/server";
import type { GetServerSidePropsContext } from "next";

export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession({ context });

if (session.isMasquerading) {
// Handle masquerade session
}

if (session.isScopedSession) {
// Handle scoped session
}

if (session.isMobileWebView) {
// Handle mobile web view session
}
}

// After
import { getSession } from "@krakentech/blueprint-auth/server";
import type { GetServerSidePropsContext } from "next";

export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession({ context });

if (session.authMethod === "masquerade") {
// Handle masquerade session
}

if (session.authMethod === "scoped") {
// Handle scoped session
}

if (session.authMethod === "mobile-web-view") {
// Handle mobile web view session
}
}
Server function factory

For a cleaner API with less boilerplate, consider using createServerSideAuth. This factory function returns pre-configured versions of all server utilities that only require runtime parameters.

Show example
// Instead of repeating config across calls
import {
getSession,
getUserScopedGraphQLClient,
} from "@krakentech/blueprint-auth/server";
import type { GetServerSidePropsContext } from "next";

export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession({ context });

const client = getUserScopedGraphQLClient({
context,
krakenConfig: {
/* ... */
},
});
}

// You can use the factory
import { createserversideauth } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";
import type { GetServerSidePropsContext } from "next";

const { getSession, getUserScopedGraphQLClient } =
createserversideauth(authConfig);

export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession({ context });
const client = getUserScopedGraphQLClient({ context });
}

See the API reference for details.

Step 7: Cookies

The cookie constants have been renamed for clarity.

// Before
import { TOKEN_COOKIE_KEYS } from "@krakentech/blueprint-auth";
const token = cookies[TOKEN_COOKIE_KEYS.access];

// After
import { AUTH_COOKIE } from "@krakentech/blueprint-auth";
const token = cookies[AUTH_COOKIE.accessToken];

Also make sure to pdate cookie names if you're manipulating auth cookies manually or in tests.

// Before
await setCookies({
cookies: [
{ name: "access", value: accessToken },
{ name: "refresh", value: refreshToken },
],
});

// After
await setCookies({
cookies: [
{ name: "accessToken", value: accessToken },
{ name: "refreshToken", value: refreshToken },
],
});

Before testing, verify all required environment variables are configured.

If you're using server-side GraphQL clients in getServerSideProps, getStaticProps, API routes, or middleware, they also need updating.

Step 8: Internationalization (i18n)

Version 40 introduces a new i18n configuration to support localized routing and pathname translation. If your app uses Next.js built-in i18n features and supports multiple locales, you need to configure the auth package accordingly.

Dedicated Guide Available

For comprehensive documentation, configuration examples, and integration patterns, see the i18n guide.

lib/auth/config.ts
import { createAuthConfig } from "@krakentech/blueprint-auth";
import { getPathname } from "@/i18n/navigation";
import { hasLocale } from "next-intl";
import { routing } from "@/i18n/routing";

export const authConfig = createAuthConfig({
i18n: {
localeCookie: "NEXT_LOCALE",
getLocalizedPathname({ locale, pathname }) {
return getPathname({
href: { pathname },
locale: hasLocale(routing.locales, locale)
? locale
: routing.defaultLocale,
});
},
},
// ... other config
});

See the i18n guide for detailed setup instructions, common patterns, and FAQ.

Step 9: Environment variables

Your environment variables remain the same, with one addition: krakenConfig.xClientIpSecretKey is now a required option. Following best practices for handling secrets, we recommend setting the KRAKEN_X_CLIENT_IP_SECRET_KEY environment variable to provide this value.

With everything in place, thoroughly test your authentication flows.

Step 10: Test everything

You know best

You know your application best. Run your type checker, build your project, and verify your authentication flows work as expected. Consider testing login, logout, token refresh, and protected routes. If you use OAuth, masquerade, organization-scoped auth, or anonymous auth features, give those a check too.

Breaking Changes Reference

Configuration Changes

Config gets organized

Options are now grouped logically into customization and validation objects. See the createAuthConfig API reference for all configuration options.

// Before
{
getCookieOptions: (cookieName) => ({ /* ... */ }),
setCustomHeaders: (headers) => { /* ... */ },
shouldValidateUrl: !process.env.IS_TEST,
}

// After
{
customization: {
getCookieOptions: (cookieName) => ({ /* ... */ }),
setCustomHeaders: (headers, authScope) => { /* ... */ },
},
validation: {
validateGraphQLEndpointUrl: !process.env.IS_TEST,
},
}
Custom headers get more context

The setCustomHeaders callback now receives authScope for user vs organization requests. This unifies the API across the package; write your header logic once and reuse it everywhere.

// Before
setCustomHeaders: (headers: Headers) => void

// After
customization: {
setCustomHeaders: (headers: Headers, authScope: "user" | "organization") => void | Promise<void>
}
Cookie options allow selective customization
// returned full context object
getCookieOptions: (cookieName: CookieName) => Omit<HttpContext, "req" | "res">;

// nested in customization, returns just cookie options
customization: {
getCookieOptions: (cookieName: CookieName) => SerializeOptions | undefined;
}
Route config gets consistent names

Route parameter extractors now use consistent naming and accept an options object for easier extensibility.

// Before
appRoutes: {
anon: {
getPreSignedKey: (url) => ({ preSignedKey }),
},
masquerade: {
getUserIdAndMasqueradeToken: (url) => ({ userId, masqueradeToken }),
},
}

// After
appRoutes: {
anon: {
getAnonParams({ url }) {
return { preSignedKey };
},
},
masquerade: {
getMasqueradeParams({ url }) {
return { userId, masqueradeToken };
},
},
}

Middleware

Middleware gets factory pattern

The middleware now uses the factory pattern with createAuthMiddleware.

// Before
import { authMiddleware } from "@krakentech/blueprint-auth/middleware";
import type { NextRequest, NextResponse } from "next/server";

export async function middleware(req: NextRequest) {
const res = NextResponse.next();
return await authMiddleware({
appRoutes: {
/* ... */
},
krakenConfig: {
/* ... */
},
req,
res,
// ... more config
});
}

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

export const middleware = createAuthMiddleware(authConfig);

export const config = {
matcher: ["/dashboard/:path*", "/login"],
};
Redirect callbacks support fallback

Before:

customSuccessResponse: ({ url }) => NextResponse.redirect(url);

After:

customSuccessResponse({ url }, { redirect }) {
if (someCondition) {
return redirect(url);
}
// return undefined to use default
}
info

The customSuccessResponse and customErrorResponse callbacks now receive helper functions (redirect, rewrite) as a second parameter. This dependency injection pattern eliminates the need to import NextResponse in your config file, making it framework-agnostic and browser-safe.

API Handlers

Handlers now use factories

Handlers are now factories that work with the unified config. You can export them directly from your API routes, reducing boilerplate code significantly. See the API reference for: createLoginHandler, createLogoutHandler, createSessionHandler, createGraphQLHandler.

// Before
import { loginHandler } from "@krakentech/blueprint-auth/server";
import type { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
await loginHandler({
krakenConfig: { graphqlEndpoint: process.env.KRAKEN_GRAPHQL_ENDPOINT },
req,
res,
edgeConfig: {
/* ... */
},
encryption: {
/* ... */
},
});
}

// After
import { createLoginHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";

export default createLoginHandler(authConfig);
GraphQL client functions split for clarity

The single getServerSideGraphQLClients function is replaced by two separate functions: getUserScopedGraphQLClient and getOrganizationScopedGraphQLClient. Import only what you need.

// Before
import { getServerSideGraphQLClients } from "@krakentech/blueprint-auth/server";

const { userScopedClient, organizationScopedClient } =
await getServerSideGraphQLClients({
krakenConfig: {
/* ... */
},
req,
res,
});

// After
import {
getUserScopedGraphQLClient,
getOrganizationScopedGraphQLClient,
} from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";

const userClient = getUserScopedGraphQLClient(authConfig, {
context: { req, res },
});

const orgClient = getOrganizationScopedGraphQLClient(authConfig, {
context: { req, res },
});

Server Functions

Server functions now use context parameter

Server-side functions now accept a context parameter as part of their options object instead of separate req and res parameters.

// Before
import { getServerSideGraphQLClients } from "@krakentech/blueprint-auth/server";

const { userScopedClient, organizationScopedClient } =
await getServerSideGraphQLClients({
krakenConfig: {
/* ... */
},
req,
res,
});

// After
import {
getUserScopedGraphQLClient,
getOrganizationScopedGraphQLClient,
} from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";

const userClient = getUserScopedGraphQLClient(authConfig, {
context: { req, res },
});

const orgClient = getOrganizationScopedGraphQLClient(authConfig, {
context: { req, res },
});

This pattern applies to all server-side utilities including getSession, getUserScopedGraphQLClient, getOrganizationScopedGraphQLClient, and others.

Client-Side Auth

Client auth uses unified config

The createClientSideAuth function signature changed from one parameter to two. The defaultTarget option moved to the second parameter along with the new router option. See the createClientSideAuth API reference for details.

// Before
import { createClientSideAuth } from "@krakentech/blueprint-auth/client";

export const { AuthProvider, useLogin, useLogout, useSession } =
createClientSideAuth({
apiRoutes: {
graphql: { kraken: "/api/graphql" },
login: "/api/auth/login",
},
defaultTarget: "kraken",
});

// After
import { createClientSideAuth } from "@krakentech/blueprint-auth/client";
import { authConfig } from "@/lib/auth/config";

export const { AuthProvider, useLogin, useLogout, useSession } =
createClientSideAuth(authConfig, {
defaultTarget: "kraken",
router: "pages-router",
});
AuthProvider API changes

The AuthProvider component API has been simplified and improved:

  1. Removed appRoutes prop - Route configuration now lives in your centralized authConfig
  2. Individual handler props - Handler callbacks are now passed as individual props directly to AuthProvider instead of being nested in a handlers object
  3. Updated handler signatures - All handlers now receive a defaultRedirect callback function, giving you control over whether to use default redirect behavior
  4. Improved error handling - The onLoginError handler receives a normalized ErrorCode string instead of a KrakenError[] array
  5. Split logout handlers - The onLogout handler splits into separate onLogoutSuccess and onLogoutError handlers for granular error handling
  6. Async support - All handlers can now be async

See the AuthProvider API reference for details.

// Before
<AuthProvider
appRoutes={{
dashboard: "/dashboard",
login: "/login",
}}
onLoginSuccess={() => {
// Handle login success
}}
onLoginError={(errorCode) => {
// Handle login error
}}
onLogoutSuccess={() => {
// Handle logout success
}}
onLogoutError={(errorCode) => {
// Handle logout error
}}
>

// After
<AuthProvider
onLoginSuccess={(defaultRedirect) => {
// Handle login success
defaultRedirect(); // Optional: use default redirect behavior
}}
onLoginError={(errorCode, defaultRedirect) => {
// Handle login error with normalized error code
defaultRedirect(); // Optional: use default redirect behavior
}}
onLogoutSuccess={(defaultRedirect) => {
// Handle logout success
defaultRedirect(); // Optional: use default redirect behavior
}}
onLogoutError={(errorCode, defaultRedirect) => {
// Handle logout error with normalized error code
defaultRedirect(); // Optional: use default redirect behavior
}}
>
useLogin accepts nextPage option

The shouldRedirectToNextPage boolean flag is replaced by nextPage for more granular redirect control. Set it to null to prevent redirect, or provide a path to redirect to a specific page. The server now returns a redirectUrl in the response. See the useLogin API reference for details.

// Before
const login = useLogin({
shouldRedirectToNextPage: false,
});

// After
const login = useLogin({
nextPage: null,
});
useLogout accepts options

The hook now accepts an options object to control redirect behavior. Use nextPage to specify the redirect destination or set it to null to prevent redirect. See the useLogout API reference for details.

// Before
const logout = useLogout();

// After
const logout = useLogout({
nextPage: "/goodbye",
});
useKrakenAuthErrorHandler uses options object

The hook now accepts an options object instead of a single callback function. The onError callback receives a defaultRedirect function as its second parameter, and you can specify redirectType ("push" or "replace"). The getAuthErrorCode function is no longer returned from the hook; import getErrorCode directly from the main package instead. See the useKrakenAuthErrorHandler API reference for details.

// Before
const { getAuthErrorCode, handleKrakenErrors } = useKrakenAuthErrorHandler(
(error) => {
// custom error handling
},
);

// After
import { getErrorCode } from "@krakentech/blueprint-auth/utils";

const { handleKrakenErrors } = useKrakenAuthErrorHandler({
onError: (error, defaultRedirect) => {
// custom error handling
},
redirectType: "replace",
});

const errorCode = getErrorCode(error);
useSession no longer refetches on window focus or reconnect

The useSession hook no longer automatically refetches session data when the user refocuses the window or reconnects to the network. This prevents UI tearing when sessions expire.

Previous behavior: The hook would refetch on refetchOnWindowFocus and refetchOnReconnect events. If the session had expired during one of these refetches, the hook would return an unauthenticated state while the user remained on a protected page (e.g., dashboard). This caused UI tearing where conditionally rendered authenticated UI elements (user menus, dashboard navigation, etc.) would suddenly disappear while the user was still viewing the page.

New behavior: The session state remains stable during the user's current page view. Users are redirected to the login page during their next page navigation or GraphQL request (when useKrakenAuthErrorHandler is used), ensuring a consistent UI experience without jarring visual changes.

See the useSession API reference for details.

Import & Export Changes

Cookie constants renamed
// TOKEN_COOKIE_KEYS with shortened property names
import { TOKEN_COOKIE_KEYS } from "@krakentech/blueprint-auth";

TOKEN_COOKIE_KEYS.access; // actually "accessToken"
TOKEN_COOKIE_KEYS.refresh; // actually "refreshToken"

// AUTH_COOKIE with full property names
import { AUTH_COOKIE } from "@krakentech/blueprint-auth";

AUTH_COOKIE.accessToken; // "accessToken"
AUTH_COOKIE.refreshToken; // "refreshToken"
Import and export names updated

The API has been redesigned for consistency. Handlers use the create* factory pattern, and utilities have clearer names.

// Utility functions renamed:
createKrakenOAuthURI → generateKrakenOAuthURI
getSessionData → getSession

// Constants renamed:
TOKEN_COOKIE_KEYSAUTH_COOKIE

// New error handling exports:
AuthError // structured error class with helpful messages
BlueprintAuthErrorCode // error code enum
getErrorCode // extract error codes from errors
isBlueprintAuthErrorCode // type guard for error codes

See the migration steps above for detailed handler and middleware changes.

getErrorCode now standalone export

The getErrorCode function is no longer returned from useKrakenAuthErrorHandler. Import it directly from the main package. See the getErrorCode API reference for details.

// Before
const { getAuthErrorCode, handleKrakenErrors } =
useKrakenAuthErrorHandler(/* ... */);
const errorCode = getAuthErrorCode(error);

// After
import { getErrorCode } from "@krakentech/blueprint-auth/utils";

const { handleKrakenErrors } = useKrakenAuthErrorHandler(/* ... */);
const errorCode = getErrorCode(error);
isBlueprintAuthErrorCode type guard

The isBlueprintAuthErrorCode function is a TypeScript type guard that checks if an error code is a valid Blueprint auth error code.

Usage:

import { isBlueprintAuthErrorCode } from "@krakentech/blueprint-auth/utils";
import type { ErrorCode } from "@krakentech/blueprint-auth";

const errorCode: string | null = getErrorCode(error);

if (isBlueprintAuthErrorCode(errorCode)) {
// errorCode is now typed as ErrorCode (not string | null)
// You get autocomplete for all valid error codes
switch (errorCode) {
case "ACCOUNT_NOT_FOUND":
// handle specific error
break;
// ...
}
}

This is useful when working with error codes from external sources or when you need strict type checking.

New SessionState

New field:

  • authMethod: Identifies which authentication method is currently active ("email", "oauth", "scoped", "masquerade", "mobile-web-view", or null)

Removed fields:

  • isMasquerading
  • isMobileWebView
  • isScopedSession
Example usage
const { data: session } = useSession();

if (session.isAuthenticated) {
return <LogoutButton />
} else {
return <LoginButton />
}

if (session.authMethod === "masquerade") {
return <MasqueradeBanner />
}

if (session.authMethod === "scoped") {
return <PaymentDetailsCard />
} else {
return <PaymentDetailsForm />
}

if (session.authMethod === "mobile-web-view") {
return <UpdateAppLink />
} else {
return <DownloadAppLink />
}

See the SessionState type reference and the AuthMethod type reference for full documentation.

New Features (Non-Breaking)

New Utility: getActiveAuthMethod

A new utility function getActiveAuthMethod is available to determine the active authentication method based on cookie priority without loading the full session state:

const { getActiveAuthMethod, getAuthCookies } = createAuthCookieUtils({
context,
});
const cookies = await getAuthCookies();
const authMethod = getActiveAuthMethod(cookies);

See the createAuthCookieUtils API reference for details on the available utility functions including getActiveAuthMethod.