Next.js session middleware
Add hosted login and an encrypted session cookie to the Next.js App Router
Use ScalekitAuthNext from @scalekit-sdk/node/next to add hosted login, an encrypted sk_session cookie, token refresh, and logout to the App Router.
Typical flow: create one auth instance, export login/callback/logout Route Handlers, and wrap a protected handler with withAuth. Use createMiddleware() to fail closed on every other path. For Edge Runtime, pass ScalekitEdgeClient instead of ScalekitClient.
Requires @scalekit-sdk/node 2.12.0 or later.
Register these URLs in the Scalekit Dashboard under Authentication > Redirects before you test:
| Dashboard field | Must match |
|---|---|
| Redirect URI | redirectUri exactly, for example http://localhost:3000/callback |
| Post Logout Redirect URI | Absolute URL after full logout, for example http://localhost:3000/ |
| Initiate Login URL | Login path, for example http://localhost:3000/login |
Store credentials in environment variables. Never hard-code secrets.
SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.comSCALEKIT_CLIENT_ID=skc_...SCALEKIT_CLIENT_SECRET=...COOKIE_ENCRYPTION_SECRET= # openssl rand -base64 32REDIRECT_URI=http://localhost:3000/callbackKeep COOKIE_ENCRYPTION_SECRET identical on every server instance.
Install the package
Section titled “Install the package”npm install @scalekit-sdk/nodeProtect a route
Section titled “Protect a route”ScalekitAuthNext requires a client. It does not accept envUrl alone.
import ScalekitClient from '@scalekit-sdk/node';import { ScalekitAuthNext } from '@scalekit-sdk/node/next';
const scalekit = new ScalekitClient( process.env.SCALEKIT_ENVIRONMENT_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!);
export const auth = new ScalekitAuthNext({ client: scalekit, redirectUri: process.env.REDIRECT_URI!, cookieEncryptionSecret: process.env.COOKIE_ENCRYPTION_SECRET!,});import { auth } from '../../lib/auth';export const GET = auth.createLoginHandler();import { auth } from '../../lib/auth';export const GET = auth.createCallbackHandler();import { auth } from '../../lib/auth';export const GET = auth.createLogoutHandler();import { auth } from '../../lib/auth';
export const GET = auth.withAuth(async (request, { user }) => { return Response.json({ sub: user?.sub });});Open http://localhost:3000/account. A missing session returns 302 to /login, not a JSON 401.
user is access-token claims. sub is always present. email appears only when you add it as a custom access-token claim.
constructor
Section titled “constructor”#constructor
Creates the App Router session helper. Pass a ScalekitClient or ScalekitEdgeClient.
Auth client. Required. ScalekitClient is Node-only; use ScalekitEdgeClient on Edge Runtime.
Exact Redirect URI registered in the dashboard.
Secret used to encrypt sk_session. Generate with openssl rand -base64 32.
Session cookie name.
Login route path.
Callback route path. Also excluded from createMiddleware() gating.
Logout route path. Also excluded from createMiddleware() gating.
Fallback path after login when returnTo is absent.
Where logout lands. Defaults to postLoginRedirect. Register the absolute URL as Post Logout Redirect URI.
When true, logout ends the Scalekit session with id_token_hint.
Helper used by Route Handlers and middleware.
export const auth = new ScalekitAuthNext({ client: scalekit, redirectUri: process.env.REDIRECT_URI!, cookieEncryptionSecret: process.env.COOKIE_ENCRYPTION_SECRET!,});createLoginHandler
Section titled “createLoginHandler”#createLoginHandler
Returns a GET Route Handler that starts hosted login and sets the CSRF state cookie.
Handler to re-export from app/login/route.ts.
export const GET = auth.createLoginHandler();createCallbackHandler
Section titled “createCallbackHandler”#createCallbackHandler
Returns a GET Route Handler that exchanges the authorization code and sets sk_session.
Handler to re-export from app/callback/route.ts.
export const GET = auth.createCallbackHandler();createLogoutHandler
Section titled “createLogoutHandler”#createLogoutHandler
Returns a GET Route Handler that clears sk_session. With fullLogout: true, also ends the Scalekit session.
Handler to re-export from app/logout/route.ts.
export const GET = auth.createLogoutHandler();withAuth
Section titled “withAuth”#asyncwithAuth
Wraps a Route Handler so it runs only with a valid session. Refreshes the cookie about 10 seconds before expiry. Redirects to loginPath when the session is missing.
Route Handler. context.user is access-token claims.
Wrapped handler. Missing session → 302, never JSON 401.
export const GET = auth.withAuth(async (request, { user }) => { return Response.json({ sub: user?.sub });});createMiddleware
Section titled “createMiddleware”#createMiddleware
Fail-closed middleware. Every matched path redirects to login unless it is listed in publicRoutes or is loginPath, callbackPath, or logoutPath.
Next.js reads export const config as a static export. This method cannot generate that object.
Paths that stay public, for example ['/', '/pricing'].
Middleware function to export as the default from middleware.ts.
export default auth.createMiddleware({ publicRoutes: ['/', '/pricing'],});
export const config = { runtime: 'nodejs', matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],};getSession
Section titled “getSession”#asyncgetSession
Read-only session lookup for Server Components, Route Handlers, and Server Actions. Does not refresh or write a cookie. Only createMiddleware() and withAuth() write a new cookie.
Access-token claims and expiry, or null. Never includes accessToken or refreshToken.
const session = await auth.getSession();if (session) { console.log(session.user.sub, session.expiresAt);}currentUser
Section titled “currentUser”#asynccurrentUser
Shortcut for getSession() when only claims are needed.
Access-token claims, or undefined when there is no valid session.
const user = await auth.currentUser();ScalekitEdgeClient
Section titled “ScalekitEdgeClient”#constructor
Fetch + jose client for the auth methods ScalekitAuthNext needs on Edge Runtime. Not a full ScalekitClient. Use Create client for Organizations, Users, and other API clients.
Scalekit environment URL.
Application client ID.
Application client secret.
Drop-in client for ScalekitAuthNext.
import { ScalekitEdgeClient } from '@scalekit-sdk/node/edge';import { ScalekitAuthNext } from '@scalekit-sdk/node/next';
const scalekit = new ScalekitEdgeClient( process.env.SCALEKIT_ENVIRONMENT_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!);
export const auth = new ScalekitAuthNext({ client: scalekit, redirectUri: process.env.REDIRECT_URI!, cookieEncryptionSecret: process.env.COOKIE_ENCRYPTION_SECRET!,});import { auth } from './lib/auth';
export default auth.createMiddleware({ publicRoutes: ['/', '/pricing'],});
export const config = { runtime: 'experimental-edge', matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],};