Skip to main content

Kraken OAuth

Configure Kraken OAuth in your Next.js app with or without a login page. Your app starts sign-in on Kraken’s hosted login screen, and Kraken redirects visitors back to complete sign-in. Customers can use the same Kraken login across applications without entering their password on each site.

Getting started​

This guide extends the Blueprint Auth setup for the Pages Router or the App Router. Complete one setup guide before you continue. Choose With a login page to offer Kraken OAuth on a /login page, or Without a login page to send unauthenticated visitors directly to Kraken.

Register an OAuth client with Kraken and obtain its client ID. Register the full callback URL for each site origin, for example https://www.example.com/api/auth/oauth/callback. The path must match apiRoutes.krakenOAuth in the configuration below.

Both setups need the same Kraken environment variables. Define them in .env.local before choosing your flow:

.env.local
KRAKEN_AUTH_ENDPOINT="https://auth.your_environment-kraken.systems/"
KRAKEN_OAUTH_CLIENT_ID="your_kraken_oauth_client_id"

Replace your_environment with your Kraken environment name and your_kraken_oauth_client_id with your registered client ID. Add the exact trusted access token issuers to validation in your existing createAuthConfig call:

lib/auth/config.ts
validation: {
accessTokenIssuers: [
"https://api.your_environment-kraken.systems/v1/graphql/",
"https://auth.your_environment-kraken.systems/token/",
"https://support.your_environment-kraken.systems",
],
},

Keep this validation entry when applying either configuration below. Alternatively, set KRAKEN_ACCESS_TOKEN_ISSUERS to these exact issuers as one comma-separated value in .env.local; the config array takes precedence.

For the OAuth issuer, add token/ to the exact Kraken auth endpoint. Replace the example domains with your environment’s values. Issuer matching is case-sensitive, including paths and trailing slashes.

Vercel Deployment

When deploying to Vercel, configure environment variables in your project dashboard rather than committing them to .env files. Follow the Vercel environment variable documentation for deployment settings.

Environment Variables

Use environment variables for supported options to keep deployment-specific values outside your code.

With a login page​

Offer Kraken OAuth on your /login page alongside any other login methods. Keep appRoutes.login so middleware sends unauthenticated visitors to that page.

Configuration​

OptionDescriptionTypeEnvironment variableRequired
krakenConfig.authEndpointKraken auth endpointstringKRAKEN_AUTH_ENDPOINT✅
krakenConfig.oauthClientIdKraken OAuth client IDstringKRAKEN_OAUTH_CLIENT_ID✅
validation.accessTokenIssuersExact trusted access token issuersstring[]KRAKEN_ACCESS_TOKEN_ISSUERS✅
apiRoutes.krakenOAuthOAuth callback routestring✅
apiRoutes.startKrakenOAuthOAuth start GET routestringPages Router link example
appRoutes.login.pathnameLogin pagestring✅

Add the OAuth callback route to the auth config from your getting-started guide. The Pages Router link example also configures startKrakenOAuth; the App Router Server Action does not need it.

Email-and-password login

The apiRoutes.login entry and its API handler are only needed if you also offer email-and-password login; keep them if you use them.

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

export const authConfig = createAuthConfig({
apiRoutes: {
graphql: { kraken: "/api/graphql/kraken" },
krakenOAuth: "/api/auth/oauth/callback",
startKrakenOAuth: "/api/auth/oauth/start",
logout: "/api/auth/logout",
session: "/api/auth/session",
},
appRoutes: {
dashboard: { pathname: "/dashboard" },
home: { pathname: "/" },
login: { pathname: "/login" },
},
});

Middleware​

Use createAuthMiddleware(authConfig) as shown in your router’s getting-started guide. Middleware protects routes and refreshes auth tokens.

Middleware redirects unauthenticated visitors from protected pages to your configured login page. Add a link or action there to start Kraken OAuth.

OAuth callback​

The callback handler verifies Kraken’s tokens and stores them as cookies. On success, it redirects to the dashboard or a saved same-origin return path. Authentication failures redirect to the login page with an error query parameter by default. To use a separate error page, configure appRoutes.oauthError and follow the public error page example.

If token verification keys are unavailable, the callback returns HTTP 503 instead of redirecting.

Create the Kraken OAuth API handler using createKrakenOAuthHandler.

pages/api/auth/oauth/callback.ts
import { createKrakenOAuthHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";

export default createKrakenOAuthHandler(authConfig);

Return path safety​

Pass nextPage when you want sign-in to return to a specific page. Blueprint Auth accepts only destinations on the request’s origin: the same scheme, host, and port. It rejects malformed or cross-origin destinations and strips fragments, storing only the path and query in oauthNextPage.

By default, the cookie expires after ten minutes; customization.getCookieOptions can override its lifetime. The callback reads, deletes, and revalidates it before processing the authorisation code. If no valid return path remains, successful sign-in redirects to the dashboard.

Initiate the OAuth flow​

When a visitor selects Kraken sign-in, the start handler or Server Action stores a one-time code verifier in a cookie. It then redirects the browser to Kraken using Proof Key for Code Exchange (PKCE).

Create a GET start handler. Route Handlers in app/ can coexist with Pages Router pages.

app/api/auth/oauth/start/route.ts
import {
createStartKrakenOAuthHandler,
} from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";

export const GET = createStartKrakenOAuthHandler(authConfig);

Add a link to your login page alongside any other login methods. Pass through the login URL’s nextPage parameter to preserve the same-origin return path:

pages/login.tsx
import type {
GetServerSidePropsContext,
InferGetServerSidePropsType,
} from "next";
import { authConfig } from "@/lib/auth/config";

export default function LoginPage({
errorCode,
startKrakenOAuthHref,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
return (
<>
{errorCode && (
<p role="alert">Sign-in failed ({errorCode}). Please try again.</p>
)}
<a href={startKrakenOAuthHref}>Log in with Kraken</a>
</>
);
}

In the same pages/login.tsx file, add getServerSideProps to build the start URL and read callback errors:

pages/login.tsx
export function getServerSideProps({ query }: GetServerSidePropsContext) {
let startKrakenOAuthHref = authConfig.apiRoutes.startKrakenOAuth;
if (typeof query.nextPage === "string") {
const nextPage = new URLSearchParams({ nextPage: query.nextPage });
startKrakenOAuthHref += `?${nextPage}`;
}

return {
props: {
errorCode: typeof query.error === "string" ? query.error : null,
startKrakenOAuthHref,
},
};
}

Without a login page​

If Kraken provides your only login screen, omit appRoutes.login and configure a public error page. The same Kraken environment variables described above apply.

Configuration​

OptionDescriptionTypeEnvironment variableRequired
krakenConfig.authEndpointKraken auth endpointstringKRAKEN_AUTH_ENDPOINT✅
krakenConfig.oauthClientIdKraken OAuth client IDstringKRAKEN_OAUTH_CLIENT_ID✅
validation.accessTokenIssuersExact trusted access token issuersstring[]KRAKEN_ACCESS_TOKEN_ISSUERS✅
apiRoutes.krakenOAuthOAuth callback routestring✅
apiRoutes.startKrakenOAuthOAuth start GET routestring✅
appRoutes.oauthError.pathnamePublic OAuth failure pagestring✅

Without a login page, configure startKrakenOAuth so server and client code can redirect visitors to sign in. OAuth setups with a login page do not always need this route. Update your existing auth config:

  1. Remove appRoutes.login. Remove apiRoutes.login if you no longer offer email-and-password login.
  2. Add apiRoutes.krakenOAuth and apiRoutes.startKrakenOAuth for the callback and start routes.
  3. Add appRoutes.oauthError.pathname for a public failure page.
  4. Keep your validation entry and the other API routes from the getting-started guide.

The following example shows the route configuration:

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

export const authConfig = createAuthConfig({
apiRoutes: {
graphql: { kraken: "/api/graphql/kraken" },
krakenOAuth: "/api/auth/oauth/callback",
startKrakenOAuth: "/api/auth/oauth/start",
logout: "/api/auth/logout",
session: "/api/auth/session",
},
appRoutes: {
dashboard: { pathname: "/dashboard" },
home: { pathname: "/" },
oauthError: { pathname: "/auth/error" },
},
});

Middleware​

Use createAuthMiddleware(authConfig) as in your router’s getting-started guide. Middleware starts OAuth directly for unauthenticated visitors to protected pages. Keep the public error page outside protected paths so callback failures do not restart the flow. Middleware requires the callback, start, and error routes above, even though it starts OAuth without requesting the start route.

OAuth callback​

Create the callback at apiRoutes.krakenOAuth using createKrakenOAuthHandler. It verifies and stores the tokens, then redirects to a saved same-origin return path or the dashboard. Authentication failures redirect to the public appRoutes.oauthError page with an error query parameter. If token verification keys are unavailable, the callback returns HTTP 503 instead of redirecting.

pages/api/auth/oauth/callback.ts
import { createKrakenOAuthHandler } from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";

export default createKrakenOAuthHandler(authConfig);

OAuth start route​

Create a separate GET Route Handler at apiRoutes.startKrakenOAuth (in app/, even if your pages use the Pages Router). Keep API routes out of the middleware matcher.

app/api/auth/oauth/start/route.ts
import {
createStartKrakenOAuthHandler,
} from "@krakentech/blueprint-auth/server";
import { authConfig } from "@/lib/auth/config";

export const GET = createStartKrakenOAuthHandler(authConfig);

Public error page​

Create a public page at appRoutes.oauthError.pathname. Keep it outside protected paths such as /dashboard to avoid restarting a failed OAuth attempt. Read the error search parameter, show a sign-in failure message, and add a retry link to apiRoutes.startKrakenOAuth. These examples display the error code for troubleshooting and link to the configured start route:

pages/auth/error.tsx
import { useRouter } from "next/router";

export default function OAuthErrorPage() {
const { query } = useRouter();
const errorCode = typeof query.error === "string" ? query.error : null;

return (
<main>
<p role="alert">
Sign-in failed{errorCode ? ` (${errorCode})` : ""}. Please try again.
</p>
<a href="/api/auth/oauth/start">Try again</a>
</main>
);
}

Initiate the OAuth flow​

Add an explicit sign-in link in either router to request a same-origin return path:

<a href="/api/auth/oauth/start?nextPage=%2Faccount">Log in with Kraken</a>

Omit nextPage to return to the dashboard by default. Protected pages start OAuth automatically through middleware.

Explanation: OAuth flow​

Kraken OAuth uses a one-time code verifier to protect sign-in without a client secret. This section explains the values and cookies behind the setup above.

No client secret required

This integration uses Proof Key for Code Exchange (PKCE). Instead of a static client secret, Blueprint Auth generates a one-time code verifier and challenge for each login. It stores the verifier in a pkceVerifier cookie. You do not need to obtain, store, or configure a client secret.

OAuth values​

NameDescription
Client IDKraken generates this public identifier when you register your application. Kraken uses it to identify your application’s requests.
Client secretSome OAuth flows use this confidential value to authenticate an application. This integration uses PKCE instead.
Redirect URIKraken sends the browser to this URL after authorisation. It must match a redirect URI you registered with Kraken.
Authorize URIYour app redirects the browser to this Kraken endpoint to start authorisation. Its query parameters include the client ID, redirect URI, and code challenge.
Code challenge

A code challenge is a cryptographic value your app generates from the code verifier and sends to Kraken during authorisation. Kraken checks that the verifier matches the challenge during the token exchange. This check prevents someone who intercepts an authorisation code from exchanging it without the verifier.

Cookies set during the flow

Blueprint Auth sets pkceVerifier when the flow starts. If you provide a same-origin return path, startKrakenOAuth stores it in oauthNextPage, which expires after ten minutes by default. The callback reads and deletes that cookie before processing the authorisation code.

After a successful exchange and token verification, Blueprint Auth sets accessToken, refreshToken, and oAuthIdToken. It does not use sub or authProvider cookies.

The Kraken auth server can set other cookies, such as octosession.

Session state​

After Kraken OAuth sign-in, Blueprint Auth sets these session fields:

FieldValueDescription
authMethod"oauth"The verified grant is OPENID-CONNECT
authSource"web"The token came from the web accessToken cookie
isAuthenticatedtrueThe request has a verified user token

See Session management for an overview of the session lifecycle.

Check the authentication method before you show method-specific user interface. Use the factory call for your router.

pages/account.tsx
import type { GetServerSidePropsContext } from "next";
import { getSession } from "@/lib/auth/server";

type AccountPageProps = { usedOAuth: boolean };

export default function AccountPage({ usedOAuth }: AccountPageProps) {
return (
<p>
{usedOAuth
? "Authenticated with OAuth"
: "Authenticated without OAuth"}
</p>
);
}

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

return {
props: {
usedOAuth: session.authMethod === "oauth",
},
};
}

FAQ​

How can I use OAuth during local development?

Kraken accepts .localhost subdomains as callback hosts, but not plain localhost. Choose one:

Run HTTPS with Portless​

Configure Portless for HTTPS, then run your app at myapp.localhost:

portless myapp next dev

Open https://myapp.localhost and register https://myapp.localhost/api/auth/oauth/callback with Kraken. Add the HTTPS origin to your existing trusted request origins in .env.local:

.env.local
ALLOWED_REQUEST_ORIGINS="https://myapp.localhost"

Run HTTPS with a hosts file and Next.js​

Add this entry to /etc/hosts or your OS’s hosts file to resolve myapp.localhost:

127.0.0.1 myapp.localhost

Start Next.js with HTTPS on that hostname:

pnpm exec next dev --experimental-https -H myapp.localhost

Open https://myapp.localhost:3000 and register https://myapp.localhost:3000/api/auth/oauth/callback with Kraken. Add that origin, including port 3000, to your existing trusted request origins:

.env.local
ALLOWED_REQUEST_ORIGINS="https://myapp.localhost:3000"

For either method, preserve other origins you need in the comma-separated list. If you set validation.allowedRequestOrigins in code, update that list instead: it takes precedence over ALLOWED_REQUEST_ORIGINS.

Match the HTTPS scheme, hostname, and port you actually use; omit the callback path. See trusted request origins for the cookie-authenticated POST handlers that require this setup. The OAuth GET routes do not require this allowlist.

Start OAuth from the registered origin: Blueprint Auth derives the callback’s scheme, host, and port from the request.

What happens when OAuth starts?

The start handler and startKrakenOAuth:

  1. Save the same-origin return path, if you provide one.
  2. Generate a one-time code verifier and challenge.
  3. Store the verifier in an HTTP-only cookie for the callback.
  4. Build the Kraken authorisation URL from the client ID and callback URL, then redirect the browser.
How is the OAuth flow initiated?

With a login page, visitors follow a link to the OAuth start handler or submit a Server Action that calls startKrakenOAuth. Without one, middleware starts OAuth for protected pages, or visitors follow a link to apiRoutes.startKrakenOAuth. In both cases, Kraken prompts them to authenticate and authorise the application.

How is the OAuth flow completed?

After a visitor authorises the application, Kraken redirects their browser to your OAuth callback with an authorisation code. The callback handler then:

  1. Reads the code verifier from the cookie.
  2. Exchanges the code and verifier for an identity token, access token, and refresh token.
  3. Removes pkceVerifier after the exchange succeeds.
  4. Verifies the identity token issuer and OAuth client ID audience.
  5. Verifies that the access token is an OAuth access token.
  6. Requires both verified tokens to have the same sub.
  7. Stores accessToken, refreshToken, and oAuthIdToken.
  8. Redirects to the saved same-origin return path or the dashboard.

Blueprint Auth does not restore pkceVerifier if token verification fails after the exchange. It does not perform an OpenID Connect nonce check.

How are errors handled?

The callback redirects authentication failures to appRoutes.oauthError when configured, or to the login page by default. Read the error query parameter and show a sign-in failure message with a retry link, as in the public error page example. If token verification keys are unavailable, the callback returns HTTP 503 instead of redirecting.

How are the tokens used?

The access token authenticates subsequent Kraken API requests. Blueprint Auth uses the refresh token to replace the access token before it expires. The accessToken cookie expiry comes from the verified exp claim.

How does Blueprint Auth refresh an access token?

Blueprint Auth sends the refresh token to Kraken before the access token expires. It verifies the replacement access token before use. If Kraken rejects an expired, invalid, or unauthorized refresh token, Blueprint Auth ends the local session. See Session management for the complete refresh failure policy.

What happens when a user logs out?

Logout removes the managed session cookies and oAuthIdToken. It keeps pkceVerifier so an OAuth flow that is in progress can finish.

Useful resources​

  1. OAuth 2.0 Simplified

  2. Modern Guide: What is OAuth 2.0 and How Does It Work?