User impersonation allows administrators to sign in as another user to troubleshoot issues or provide support. AuthKit provides built-in components and APIs to handle impersonation securely.
Displaying impersonation status
Use the Impersonation component to show when an admin is impersonating a user:
import { AuthKitProvider, Impersonation } from '@workos-inc/authkit-nextjs/components';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<AuthKitProvider>
<Impersonation />
{children}
</AuthKitProvider>
</body>
</html>
);
}
The component automatically:
- Displays when an impersonation session is active
- Shows the impersonated user’s email and organization
- Provides a “Stop” button to end impersonation
- Can be minimized to reduce screen space
The Impersonation component only renders when an active impersonation session is detected. It has no visual impact during normal user sessions.
Customizing the impersonation banner
Control the banner’s position and return URL:
import { Impersonation } from '@workos-inc/authkit-nextjs/components';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
{/* Display at top of page */}
<Impersonation side="top" returnTo="/admin/users" />
{children}
{/* Or display at bottom (default) */}
{/* <Impersonation side="bottom" returnTo="/admin" /> */}
</div>
);
}
Styling the impersonation banner
Customize the appearance using CSS custom properties:
/* styles/globals.css */
[data-workos-impersonation-root] {
--workos-impersonation-size: 6px;
--workos-impersonation-background-color: #fce654;
--workos-impersonation-color: #1a1600;
--workos-impersonation-border-color: #e0c36c;
--workos-impersonation-border-width: 2px;
}
Available CSS custom properties:
| Property | Default | Description |
|---|
--workos-impersonation-size | 4px | Frame border size (2px-15px) |
--workos-impersonation-background-color | #fce654 | Banner background color |
--workos-impersonation-color | #1a1600 | Text color |
--workos-impersonation-border-color | #e0c36c | Border color |
--workos-impersonation-border-width | 1px | Border width |
Detecting impersonation in server components
Check if the current session is an impersonation session:
import { withAuth } from '@workos-inc/authkit-nextjs';
export default async function UserProfile() {
const { user, impersonator } = await withAuth({ ensureSignedIn: true });
return (
<div>
{impersonator && (
<div className="impersonation-alert">
<strong>Impersonation Active</strong>
<p>
{impersonator.email} is viewing this page as {user.email}
</p>
</div>
)}
<h1>User Profile</h1>
<p>Email: {user.email}</p>
<p>Name: {user.firstName} {user.lastName}</p>
</div>
);
}
Detecting impersonation in client components
Use the useAuth hook to check for impersonation:
'use client';
import { useAuth } from '@workos-inc/authkit-nextjs/components';
export default function Dashboard() {
const { user, impersonator, loading } = useAuth();
if (loading) return <div>Loading...</div>;
if (!user) return <div>Not authenticated</div>;
return (
<div>
{impersonator && (
<div className="alert alert-warning">
Admin {impersonator.email} is impersonating {user.email}
</div>
)}
<h1>Dashboard</h1>
<p>Welcome, {user.firstName}!</p>
</div>
);
}
The impersonator object contains:
| Property | Type | Description |
|---|
email | string | Email of the admin performing impersonation |
reason | string | null | Optional reason provided for impersonation |
import { withAuth } from '@workos-inc/authkit-nextjs';
export default async function AuditLog() {
const { user, impersonator } = await withAuth({ ensureSignedIn: true });
if (impersonator) {
console.log('Impersonation details:', {
admin: impersonator.email,
targetUser: user.email,
reason: impersonator.reason || 'No reason provided',
});
}
return <div>Audit Log</div>;
}
Ending impersonation
The built-in Impersonation component includes a stop button. You can also end impersonation programmatically:
Server-side
import { signOut } from '@workos-inc/authkit-nextjs';
export default function StopImpersonationButton() {
return (
<form
action={async () => {
'use server';
await signOut({ returnTo: '/admin/users' });
}}
>
<button type="submit">Stop impersonating</button>
</form>
);
}
Client-side
'use client';
import { useAuth } from '@workos-inc/authkit-nextjs/components';
export default function StopImpersonationButton() {
const { impersonator, signOut } = useAuth();
if (!impersonator) return null;
return (
<button onClick={() => signOut({ returnTo: '/admin/users' })}>
Stop impersonating
</button>
);
}
Calling signOut during an impersonation session ends the impersonation and returns the admin to their own session.
Conditional features during impersonation
Disable or modify certain features when impersonating:
import { withAuth } from '@workos-inc/authkit-nextjs';
export default async function SettingsPage() {
const { user, impersonator } = await withAuth({ ensureSignedIn: true });
return (
<div>
<h1>Settings</h1>
{impersonator ? (
<div className="readonly-mode">
<p>Viewing in read-only mode (impersonation active)</p>
<p>User: {user.email}</p>
<p>Admin: {impersonator.email}</p>
</div>
) : (
<form>
<input name="email" defaultValue={user.email} />
<button type="submit">Save changes</button>
</form>
)}
</div>
);
}
Logging impersonation events
Track impersonation sessions for security and compliance:
import { withAuth } from '@workos-inc/authkit-nextjs';
import { headers } from 'next/headers';
export default async function ProtectedPage() {
const { user, impersonator, sessionId } = await withAuth({ ensureSignedIn: true });
if (impersonator) {
const headersList = await headers();
const userAgent = headersList.get('user-agent');
await logImpersonationEvent({
admin: impersonator.email,
targetUser: user.email,
sessionId,
userAgent,
timestamp: new Date(),
reason: impersonator.reason,
});
}
return <div>Protected content</div>;
}
Starting impersonation
Impersonation is started through the WorkOS dashboard or API, not directly in your Next.js app. See the WorkOS impersonation documentation for details on initiating impersonation sessions.
Enable impersonation in WorkOS
Configure impersonation settings in the WorkOS dashboard under User Management settings.
Use the WorkOS API or dashboard to start an impersonation session:
import { getWorkOS } from '@workos-inc/authkit-nextjs';
export async function startImpersonation(userId: string, reason: string) {
const workos = getWorkOS();
const { url } = await workos.userManagement.createPortalSession({
organizationId: 'org_123',
userId,
returnUrl: 'https://example.com/admin/users',
});
return url;
}
Your Next.js app automatically detects impersonation sessions through AuthKit. Display the impersonation banner and handle the session accordingly.
Best practices
Always display a clear visual indicator when impersonation is active. Users (and admins) should never be confused about whose account is currently active.
Security considerations:
- Log all impersonation events for audit purposes
- Require a reason for impersonation when possible
- Limit impersonation to specific admin roles
- Consider disabling sensitive operations during impersonation
- Set up alerts for impersonation sessions
The impersonation session has the same permissions and access as the impersonated user. Be cautious when impersonating users with elevated privileges.