Masquerade Authentication
Introduction
Masquerade authentication enables authorized staff members to temporarily impersonate users for customer support and troubleshooting purposes. Unlike standard login which uses email/password credentials, masquerade auth creates authenticated sessions using pre-generated masquerade tokens, providing staff with secure access to user accounts.
- Session-based: Creates standard authenticated sessions with
authMethodfor tracking - Secure token handling: Tokens are invalidated on error and require fresh authentication
Getting started
Complete the Getting Started: Pages Router or Getting Started: App Router guide
Configuration
Basic Configuration
import { createAuthConfig } from "@krakentech/blueprint-auth";
export const authConfig = createAuthConfig({
appRoutes: {
dashboard: { pathname: "/dashboard" },
login: { pathname: "/login" },
masquerade: {
// Extract userId and masqueradeToken from URL path
getMasqueradeParams({ url }) {
const [_masquerade, userId, masqueradeToken] = url.pathname
.split("/")
.filter(Boolean);
return { userId, masqueradeToken };
},
// Pathname where masquerade URLs are handled
pathname: "/masquerade",
},
},
});
Advanced Configuration (with custom redirects)
import { createAuthConfig } from "@krakentech/blueprint-auth";
import { NextResponse } from "next/server";
export const authConfig = createAuthConfig({
appRoutes: {
dashboard: { pathname: "/dashboard" },
login: { pathname: "/login" },
masquerade: {
getMasqueradeParams({ url }) {
const [_masquerade, userId, masqueradeToken] = url.pathname.split("/");
if (userId && masqueradeToken) {
return { userId, masqueradeToken };
}
},
pathname: "/masquerade",
// Optional: Custom redirect on success
customSuccessResponse({ url }, { redirect }) {
// Example: redirect to dashboard home page
return redirect(new URL("/dashboard", url.origin));
},
// Optional: Custom error handling
customErrorResponse({ url, errorCode }, { redirect }) {
return redirect(new URL(`/login?code=${errorCode}`, url.origin));
},
},
},
});
Configuration Options
| Option | Type | Required | Description |
|---|---|---|---|
pathname | string | ✅ | Route where masquerade auth is handled |
getMasqueradeParams | (options: { url: NextURL }) => { userId: string | null | undefined; masqueradeToken: string | null | undefined } | undefined | ✅ | Extracts userId and masqueradeToken from URL |
customSuccessResponse | (options: { url: NextURL }, helpers: { redirect, rewrite }) => NextResponse | undefined | ❌ | Override redirect after successful authentication |
customErrorResponse | (options: { url: NextURL; errorCode: ErrorCode }, helpers: { redirect, rewrite }) => NextResponse | undefined | ❌ | Override redirect on authentication failure |
Middleware
- Next.js ≤15
- Next.js 16+
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", "/masquerade/:path*"],
};
import { createAuthMiddleware } from "@krakentech/blueprint-auth/middleware";
import { authConfig } from "@/lib/auth/config";
export const proxy = createAuthMiddleware(authConfig);
export const config = {
matcher: ["/dashboard/:path*", "/login", "/masquerade/:path*"],
};
The middleware matcher array must include your appRoutes.masquerade.pathname
value, otherwise the masquerade auth flow won't trigger.
Masquerade route
Create a page that handles the masquerade authentication flow. The middleware
automatically authenticates the user and sets the masqueradeToken cookie when
staff navigate to the masquerade URL. After successful authentication, the page
typically redirects users to the dashboard.
- Pages Router
- App Router
import type { GetServerSidePropsContext } from "next";
import { getUserScopedGraphQLClient } from "@/lib/auth/server";
import { graphql } from "@/lib/graphql";
// This page component never renders - users are redirected in getServerSideProps
export default function MasqueradePage() {
return null;
}
const ViewerQuery = graphql(`
query MasqueradeViewer {
viewer {
accounts {
number
}
}
}
`);
export async function getServerSideProps(
context: GetServerSidePropsContext<{
userId: string;
masqueradeToken: string;
}>,
) {
// The masqueradeToken cookie is already set by middleware
// Fetch the user's first account and redirect to dashboard
const graphQLClient = getUserScopedGraphQLClient({ context });
const { viewer } = await graphQLClient.request(ViewerQuery);
const accountNumber = viewer?.accounts?.at(0)?.number;
if (!accountNumber) {
return {
redirect: {
destination: "/login",
permanent: false,
},
};
}
return {
redirect: {
destination: `/dashboard/accounts/${accountNumber}`,
permanent: false,
},
};
}
import { redirect } from "next/navigation";
import { getUserScopedGraphQLClient } from "@/lib/auth/server";
import { graphql } from "@/lib/graphql";
const ViewerQuery = graphql(`
query MasqueradeViewer {
viewer {
accounts {
number
}
}
}
`);
export default async function MasqueradePage() {
const graphQLClient = getUserScopedGraphQLClient();
const { viewer } = await graphQLClient.request(ViewerQuery);
const accountNumber = viewer?.accounts?.at(0)?.number;
if (!accountNumber) {
redirect("/login");
}
redirect(`/dashboard/${accountNumber}`);
}
The middleware handles authentication automatically when staff navigate to
/masquerade/{userId}/{masqueradeToken}. Your page component only needs to
handle the post-authentication redirect.
Session state
The middleware ensures staff have valid masquerade tokens before reaching your page components. You don't need to check session state for security purposes.
Checking session state is useful when you need to display masquerade-specific UI
elements or track staff activity. Use getSession or useSession to
conditionally render masquerade indicators and apply different behavior for
masqueraded sessions.
Session state fields
| Field | Value | Description |
|---|---|---|
authMethod | "masquerade" | Indicates staff member is authenticated via masquerade |
isAuthenticated | true | User has valid authentication (any supported auth cookie) |
Masquerade authentication has the highest priority among all authentication methods. When a masquerade URL is accessed, any existing authentication (including full login sessions, scoped tokens, or mobile web view tokens) is cleared and replaced with the masquerade session. This ensures clean session state and prevents conflicts between the staff member's own account and the masqueraded user account.
Priority order:
masquerade- Highest priority (current method)mobile-web-view- Mobile app integrationoauthoremail- Full authenticated sessionsscoped- Anonymous/pre-signed key access
Common patterns
- Masquerade Indicator
- Conditional Features
- Server-Side Checks
Display a visual indicator when staff are masquerading to prevent confusion and ensure they're aware they're viewing a customer's account.
A header component that displays a prominent masquerade banner when staff are impersonating a user, helping prevent accidental actions on customer accounts.
Show implementation
"use client";
import { useSession } from "@/lib/auth/client";
import { Logo } from "@/components/Logo";
import { LogoutButton } from "@/components/LogoutButton";
import { MasqueradeBadge } from "@/components/MasqueradeBadge";
import { NavigationMenu } from "@/components/NavigationMenu";
export function Header() {
const {
data: { isAuthenticated, authMethod },
} = useSession();
return (
<header>
{authMethod === "masquerade" && <MasqueradeBadge />}
<NavigationMenu />
<Logo />
{isAuthenticated && <LogoutButton />}
</header>
);
}
Disable or modify features when staff are masquerading to prevent unintended actions or provide staff-specific functionality.
A billing page that prevents payment method changes during masquerade sessions but allows viewing payment information for support purposes.
Show implementation
import type { GetServerSidePropsContext } from "next";
import { getSession, getUserScopedGraphQLClient } from "@/lib/auth/server";
import { graphql } from "@/lib/graphql";
import { PaymentMethods } from "@/components/PaymentMethods";
const BillingQuery = graphql(`
query BillingPage($accountNumber: String!) {
account(accountNumber: $accountNumber) {
id
number
paymentMethods {
id
type
lastFourDigits
}
}
}
`);
export default async function BillingPage({
account,
isMasquerading,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
return (
<div>
<h1>Billing Information</h1>
<PaymentMethods
methods={account.paymentMethods}
readOnly={isMasquerading}
/>
</div>
);
}
export async function getServerSideProps(
context: GetServerSidePropsContext<{ accountNumber: string }>,
) {
const { authMethod } = await getSession({ context });
const { accountNumber } = context.params;
const graphQLClient = getUserScopedGraphQLClient({ context });
const { account } = await graphQLClient.request(BillingQuery, {
accountNumber,
});
return {
props: {
account,
isMasquerading: authMethod === "masquerade",
},
};
}
Server-side operations need different behavior when staff are masquerading, such as bypassing certain validations or applying special business rules.
A server action that allows viewing sensitive customer information during masquerade sessions but requires additional verification for regular users.
Show implementation
"use server";
import { getSession, getUserScopedGraphQLClient } from "@/lib/auth/server";
import { graphql } from "@/lib/graphql";
const SensitiveDataQuery = graphql(`
query GetSensitiveData($accountId: ID!) {
account(id: $accountId) {
id
personalDetails {
email
phoneNumber
address
}
}
}
`);
export async function getSensitiveData(accountNumber: string) {
const session = await getSession();
// Staff can view without additional verification
if (session.authMethod === "masquerade") {
const graphQLClient = getUserScopedGraphQLClient();
return graphQLClient.request(SensitiveDataQuery, { accountNumber });
}
// Regular users need to verify their identity
throw new Error("Additional verification required");
}
Security Considerations
- Token sensitivity: Masquerade tokens grant full account access - handle with the same security as passwords
- HTTPS only: Never transmit masquerade tokens over unencrypted connections
- Token invalidation: Tokens are automatically cleared on authentication errors
- No token refresh: Masquerade tokens cannot be refreshed - staff must re-authenticate
FAQ
How does masquerade authentication work?
- Staff clicks masquerade button in Kraken support site, which navigates to
masquerade URL with embedded token (e.g.,
/masquerade/{userId}/{masqueradeToken}) - Next.js middleware intercepts the request
getMasqueradeParamsfunction extractsuserIdandmasqueradeTokenfrom URL- Middleware calls
masqueradeAuthenticationGraphQL mutation with the token and user ID - Kraken validates the token and user ID, returns a session token
- Middleware sets
masqueradeTokenandauthProvider=masqueradecookies - Staff gains authenticated access to the user's account
- Session persists until logout or masquerade token expiration
What happens if a staff member is already authenticated?
When a masquerade URL is accessed, the middleware removes all existing auth cookies and establishes a fresh masquerade session. This ensures clean session state and prevents conflicts between staff's own account and the masqueraded user account.
How do staff exit masquerade mode?
Staff exit masquerade mode by using the standard logout functionality. Call the
logout mutation or use the useLogout hook, which clears all authentication
cookies including the masquerade token.
What happens when a masquerade token is invalid?
When an invalid masquerade token is provided:
- Authentication fails at the middleware level
- The
masqueradeTokenandauthProvidercookies are cleared (even if a valid token from another session exists) - User is redirected to the login page (or custom error page if configured)
- Staff must obtain a new masquerade token to retry
Next Steps
Now that you have masquerade authentication configured, explore these related guides:
- Anonymous Auth: Enable pre-signed key authentication for temporary access
- Kraken OAuth: Enable OAuth-based authentication flows
- Organization-Scoped Auth: Restrict authentication to specific organizations
- Building Forms: Create production-ready forms with validation and error handling
API Reference
Quick reference to relevant functions:
createAuthConfig: Configure masquerade auth routescreateAuthMiddleware: Enable middleware handlinggetSession: Check session state (isAuthenticated,authMethod)getUserScopedGraphQLClient: Make authenticated GraphQL requests with masquerade token