{"id":18321101,"url":"https://github.com/workos/authkit-nextjs","last_synced_at":"2026-01-07T19:16:11.297Z","repository":{"id":228401728,"uuid":"772567894","full_name":"workos/authkit-nextjs","owner":"workos","description":"The WorkOS library for Next.js provides convenient helpers for authentication and session management using WorkOS \u0026 AuthKit with Next.js.","archived":false,"fork":false,"pushed_at":"2025-10-29T01:10:19.000Z","size":1119,"stargazers_count":124,"open_issues_count":31,"forks_count":44,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-10-29T02:39:38.481Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/workos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-03-15T13:00:41.000Z","updated_at":"2025-10-24T15:16:02.000Z","dependencies_parsed_at":"2024-05-30T13:22:44.161Z","dependency_job_id":"16723a00-6741-4e19-9b91-2936c6c90aad","html_url":"https://github.com/workos/authkit-nextjs","commit_stats":{"total_commits":95,"total_committers":16,"mean_commits":5.9375,"dds":0.6631578947368422,"last_synced_commit":"4b9a45d239370fe26c94e4412f8f64172ddc7a02"},"previous_names":["workos/workos-nextjs","workos/authkit-nextjs"],"tags_count":78,"template":false,"template_full_name":null,"purl":"pkg:github/workos/authkit-nextjs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauthkit-nextjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauthkit-nextjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauthkit-nextjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauthkit-nextjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/workos","download_url":"https://codeload.github.com/workos/authkit-nextjs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauthkit-nextjs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284115869,"owners_count":26949957,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-12T02:00:06.336Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T18:18:20.448Z","updated_at":"2026-01-07T19:16:11.289Z","avatar_url":"https://github.com/workos.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AuthKit Next.js Library\n\nThe AuthKit library for Next.js provides convenient helpers for authentication and session management using WorkOS \u0026 AuthKit with Next.js.\n\n\u003e Note: This library is intended for use with the Next.js App Router.\n\n## Installation\n\nInstall the package with:\n\n```\nnpm i @workos-inc/authkit-nextjs\n```\n\nor\n\n```\nyarn add @workos-inc/authkit-nextjs\n```\n\n## Video tutorial\n\n\u003ca href=\"https://youtu.be/W8TmptLkEvA?feature=shared\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/08c77835-1140-412a-baa9-a587ab27fc5e\" alt=\"YouTube tutorial: Next.js App Router Authentication with AuthKit\" style=\"display: block; width: 100%; max-width: 720px; height: auto; aspect-ratio: 16/9; object-fit: cover; object-position: center; margin: 1em auto;\" onerror=\"this.onerror=null; this.src='https://i3.ytimg.com/vi/W8TmptLkEvA/maxresdefault.jpg'\" /\u003e\n\u003c/a\u003e\n\n## Pre-flight\n\nMake sure the following values are present in your `.env.local` environment variables file. The client ID and API key can be found in the [WorkOS dashboard](https://dashboard.workos.com), and the redirect URI can also be configured there.\n\n```sh\nWORKOS_CLIENT_ID=\"client_...\" # retrieved from the WorkOS dashboard\nWORKOS_API_KEY=\"sk_test_...\" # retrieved from the WorkOS dashboard\nWORKOS_COOKIE_PASSWORD=\"\u003cyour password\u003e\" # generate a secure password here\nNEXT_PUBLIC_WORKOS_REDIRECT_URI=\"http://localhost:3000/callback\" # configured in the WorkOS dashboard\n```\n\n`WORKOS_COOKIE_PASSWORD` is the private key used to encrypt the session cookie. It has to be at least 32 characters long. You can use the [1Password generator](https://1password.com/password-generator/) or the `openssl` library to generate a strong password via the command line:\n\n```\nopenssl rand -base64 24\n```\n\nTo use the `signOut` method, you'll need to set a default Logout URI in your WorkOS dashboard settings under \"Redirects\".\n\n### Optional configuration\n\nCertain environment variables are optional and can be used to debug or configure cookie settings.\n\n| Environment Variable     | Default Value         | Description                                                                               |\n| ------------------------ | --------------------- | ----------------------------------------------------------------------------------------- |\n| `WORKOS_COOKIE_MAX_AGE`  | `34560000` (400 days) | Maximum age of the cookie in seconds                                                      |\n| `WORKOS_COOKIE_DOMAIN`   | None                  | Domain for the cookie. When empty, the cookie is only valid for the current domain        |\n| `WORKOS_COOKIE_NAME`     | `'wos-session'`       | Name of the session cookie                                                                |\n| `WORKOS_API_HOSTNAME`    | `'api.workos.com'`    | Base WorkOS API URL                                                                       |\n| `WORKOS_API_HTTPS`       | `true`                | Whether to use HTTPS in API calls                                                         |\n| `WORKOS_API_PORT`        | None                  | Port to use for API calls. When not set, uses standard ports (443 for HTTPS, 80 for HTTP) |\n| `WORKOS_COOKIE_SAMESITE` | `'lax'`               | SameSite attribute for cookies. Options: `'lax'`, `'strict'`, or `'none'`                 |\n\nExample usage:\n\n```sh\nWORKOS_COOKIE_MAX_AGE='600'\nWORKOS_COOKIE_DOMAIN='example.com'\nWORKOS_COOKIE_NAME='my-auth-cookie'\n```\n\n\u003e [!WARNING]\n\u003e Setting `WORKOS_COOKIE_SAMESITE='none'` allows cookies to be sent in cross-origin contexts (like iframes), but reduces protection against CSRF attacks. This setting forces cookies to be secure (HTTPS only) and should only be used when absolutely necessary for your application architecture.\n\n\u003e [!TIP] \u003e`WORKOS_COOKIE_DOMAIN` can be used to share WorkOS sessions between apps/domains. Note: The `WORKOS_COOKIE_PASSWORD` would need to be the same across apps/domains. Not needed for most use cases.\n\n## Setup\n\n### Callback route\n\nWorkOS requires that you have a callback URL to redirect users back to after they've authenticated. In your Next.js app, [expose an API route](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) and add the following.\n\n```ts\nimport { handleAuth } from '@workos-inc/authkit-nextjs';\n\nexport const GET = handleAuth();\n```\n\nMake sure this route matches the `WORKOS_REDIRECT_URI` variable and the configured redirect URI in your WorkOS dashboard. For instance if your redirect URI is `http://localhost:3000/auth/callback` then you'd put the above code in `/app/auth/callback/route.ts`.\n\nYou can also control the pathname the user will be sent to after signing-in by passing a `returnPathname` option to `handleAuth` like so:\n\n```ts\nexport const GET = handleAuth({ returnPathname: '/dashboard' });\n```\n\nIf your application needs to persist data upon a successful authentication, like the `oauthTokens` from an upstream provider, you can pass in a `onSuccess` function that will get called after the user has successfully authenticated:\n\n```ts\nexport const GET = handleAuth({\n  onSuccess: async ({ user, oauthTokens, authenticationMethod, organizationId, state }) =\u003e {\n    await saveTokens(oauthTokens);\n    if (authenticationMethod) {\n      await saveAuthMethod(user.id, authenticationMethod);\n    }\n    // Access custom state data passed through the auth flow\n    const customData = state ? JSON.parse(state) : null;\n    if (customData?.teamId) {\n      await addUserToTeam(user.id, customData.teamId);\n    }\n  },\n});\n```\n\nWhen running in environments like Docker, set the `baseURL` explicitly to ensure the redirects point to the correct location.\n\n```ts\nexport const GET = handleAuth({\n  baseURL: 'http://localhost:3000',\n});\n```\n\n`handleAuth` can be used with the following options.\n\n| Option           | Default     | Description                                                                                                                                                                                                 |\n| ---------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `returnPathname` | `/`         | The pathname to redirect the user to after signing in                                                                                                                                                       |\n| `baseURL`        | `undefined` | The base URL to use for the redirect URI instead of the one in the request. **Required** if the app is being run in a container like docker where the hostname can be different from the one in the request |\n| `onSuccess`      | `undefined` | A function that receives successful authentication data and can be used for side-effects like persisting tokens                                                                                             |\n| `onError`        | `undefined` | A function that can receive the error and the request and handle the error in its own way.                                                                                                                  |\n\n#### onSuccess callback data\n\nThe `onSuccess` callback receives the following data:\n\n| Property               | Type                        | Description                                                                                        |\n| ---------------------- | --------------------------- | -------------------------------------------------------------------------------------------------- |\n| `user`                 | `User`                      | The authenticated user object                                                                      |\n| `accessToken`          | `string`                    | JWT access token                                                                                   |\n| `refreshToken`         | `string`                    | Refresh token for session renewal                                                                  |\n| `impersonator`         | `Impersonator \\| undefined` | Present if user is being impersonated                                                              |\n| `oauthTokens`          | `OauthTokens \\| undefined`  | OAuth tokens from upstream provider                                                                |\n| `authenticationMethod` | `string \\| undefined`       | How the user authenticated (e.g., 'password', 'google-oauth'). Only available during initial login |\n| `organizationId`       | `string \\| undefined`       | Organization context of authentication                                                             |\n| `state`                | `string \\| undefined`       | Custom state string passed through the authentication flow (parse with JSON.parse if needed)       |\n\n**Note**: `authenticationMethod` is only provided during the initial authentication callback. It will not be available in subsequent requests or session refreshes.\n\n### Proxy / Middleware\n\nThis library relies on Next.js proxy (called \"middleware\" in Next.js ≤15) to provide session management for routes.\n\n**For Next.js 16+:** Create a `proxy.ts` file in the root of your project.\n**For Next.js ≤15:** Create a `middleware.ts` file in the root of your project.\n\nThe code remains the same; only the filename and export name differ:\n\n```ts\n// proxy.ts (Next.js 16+) or middleware.ts (Next.js ≤15)\nimport { authkitMiddleware } from '@workos-inc/authkit-nextjs';\n\nexport default authkitMiddleware();\n// For Next.js 16+, you can also use: export { default as proxy } from './proxy';\n\n// Match against pages that require auth\n// Leave this out if you want auth on every resource (including images, css etc.)\nexport const config = { matcher: ['/', '/admin'] };\n```\n\nThe proxy/middleware can be configured with several options.\n\n| Option           | Default     | Description                                                                                                             |\n| ---------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------- |\n| `redirectUri`    | `undefined` | Used in cases where you need your redirect URI to be set dynamically (e.g. Vercel preview deployments)                  |\n| `middlewareAuth` | `undefined` | Used to configure proxy/middleware auth options. See [middleware auth](#middleware-auth) for more details.              |\n| `debug`          | `false`     | Enables debug logs.                                                                                                     |\n| `signUpPaths`    | `[]`        | Used to specify paths that should use the 'sign-up' screen hint when redirecting to AuthKit.                            |\n| `eagerAuth`      | `false`     | Enables synchronous access token availability for third-party services. See [eager auth](#eager-auth) for more details. |\n\n#### Custom redirect URI\n\nIn cases where you need your redirect URI to be set dynamically (e.g. Vercel preview deployments), use the `redirectUri` option in `authkitMiddleware`:\n\n```ts\nimport { authkitMiddleware } from '@workos-inc/authkit-nextjs';\n\nexport default authkitMiddleware({\n  redirectUri: 'https://foo.example.com/callback',\n});\n\n// Match against pages that require auth\n// Leave this out if you want auth on every resource (including images, css etc.)\nexport const config = { matcher: ['/', '/admin'] };\n```\n\nCustom redirect URIs will be used over a redirect URI configured in the environment variables.\n\n#### Composable proxy/middleware\n\nIf you need to combine AuthKit with other proxy logic (rate limiting, redirects, etc.), use the `authkit()` function with `handleAuthkitHeaders()` helper:\n\n```ts\n// proxy.ts (Next.js 16+) or middleware.ts (Next.js ≤15)\nimport { NextRequest } from 'next/server';\nimport { authkit, handleAuthkitHeaders } from '@workos-inc/authkit-nextjs';\n\nexport default async function proxy(request: NextRequest) {\n  // For Next.js ≤15, use: export default async function middleware(request: NextRequest) {\n  // Get session, headers, and the WorkOS authorization URL for sign-in redirects\n  const { session, headers, authorizationUrl } = await authkit(request);\n\n  const { pathname } = request.nextUrl;\n\n  // Redirect unauthenticated users on protected routes\n  if (pathname.startsWith('/app') \u0026\u0026 !session.user \u0026\u0026 authorizationUrl) {\n    return handleAuthkitHeaders(request, headers, { redirect: authorizationUrl });\n  }\n\n  // Custom redirects (relative URLs supported)\n  if (pathname === '/old-path') {\n    return handleAuthkitHeaders(request, headers, { redirect: '/new-path' });\n  }\n\n  // Continue request with properly merged headers\n  return handleAuthkitHeaders(request, headers);\n}\n\nexport const config = { matcher: ['/', '/app/:path*'] };\n```\n\n\u003e [!IMPORTANT]\n\u003e Always use `handleAuthkitHeaders()` when returning a response. This helper ensures:\n\u003e\n\u003e - AuthKit headers are properly passed to your pages (so `withAuth()` works)\n\u003e - Internal headers (session data, URLs) are never leaked to the browser\n\u003e - Only safe response headers (`Set-Cookie`, `Cache-Control`, `Vary`) are forwarded\n\u003e - `Cache-Control: no-store` is automatically set when cookies are present\n\u003e - `Vary` headers are properly merged when multiple values exist\n\u003e - Relative redirect URLs are automatically normalized to absolute URLs\n\u003e - POST/PUT redirects use 303 status to prevent form resubmission\n\n\u003e [!NOTE]\n\u003e The `redirect` option should only be used with trusted values (e.g., `authorizationUrl` from `authkit()` or hardcoded paths). Never pass user-controlled input directly to `redirect` without validation, as this could enable open redirect attacks.\n\n##### Redirect options\n\n```ts\nhandleAuthkitHeaders(request, headers, {\n  redirect: '/login', // URL to redirect to (string or URL object)\n  redirectStatus: 307, // 302 | 303 | 307 | 308 (default: 307 for GET, 303 for POST)\n});\n```\n\n##### Advanced: Composing with rewrites\n\nFor advanced use cases like rewrites, use the lower-level `partitionAuthkitHeaders()` and `applyResponseHeaders()`:\n\n```ts\n// proxy.ts (Next.js 16+) or middleware.ts (Next.js ≤15)\nimport { NextRequest, NextResponse } from 'next/server';\nimport { authkit, partitionAuthkitHeaders, applyResponseHeaders } from '@workos-inc/authkit-nextjs';\n\nexport default async function proxy(request: NextRequest) {\n  // For Next.js ≤15, use: export default async function middleware(request: NextRequest) {\n  const { headers } = await authkit(request);\n  const { requestHeaders, responseHeaders } = partitionAuthkitHeaders(request, headers);\n\n  // Create your own response (rewrite, etc.)\n  const response = NextResponse.rewrite(new URL('/app/dashboard', request.url), {\n    request: { headers: requestHeaders },\n  });\n\n  // Apply AuthKit response headers (Set-Cookie, etc.)\n  applyResponseHeaders(response, responseHeaders);\n\n  return response;\n}\n```\n\n##### Internal headers reference\n\nAuthKit uses internal headers to pass data between proxy/middleware and server components. These are automatically handled by the helpers above, but understanding them helps with debugging.\n\n**Request headers** (passed to server components, never sent to browser):\n\n| Header                | Purpose                                                                                    |\n| --------------------- | ------------------------------------------------------------------------------------------ |\n| `x-workos-middleware` | Flag indicating AuthKit proxy/middleware is active. Required for `withAuth()` to function. |\n| `x-workos-session`    | Encrypted session data. Contains user info, access token, and refresh token.               |\n| `x-url`               | Current request URL. Used for redirect-after-login and generating sign-in URLs.            |\n| `x-redirect-uri`      | OAuth callback URI. Used by `getAuthorizationUrl()` for the OAuth flow.                    |\n| `x-sign-up-paths`     | Paths configured to trigger sign-up instead of sign-in flow.                               |\n\n\u003e **Security:** These headers contain sensitive session data. The `handleAuthkitHeaders()` helper ensures they're forwarded to your pages (so `withAuth()` works) but never leaked to the browser. Client-injected `x-workos-*` headers are stripped and replaced with trusted values.\n\n**Response headers** (safe to send to browser):\n\n| Header               | Purpose                                                                                |\n| -------------------- | -------------------------------------------------------------------------------------- |\n| `Set-Cookie`         | Session cookies (e.g., `wos-session`). Multiple cookies are properly appended.         |\n| `Cache-Control`      | Caching directives. Auto-set to `no-store` when cookies are present.                   |\n| `Vary`               | Cache variation keys. Values are deduplicated when merging.                            |\n| `WWW-Authenticate`   | Authentication challenge for 401 responses (API auth flows).                           |\n| `Proxy-Authenticate` | Authentication challenge for proxy auth.                                               |\n| `Link`               | Pagination, preload hints, etc.                                                        |\n| `x-middleware-cache` | Next.js proxy/middleware result caching. Set to `no-cache` to prevent stale responses. |\n\nOnly these allowlisted headers are forwarded to the browser. Any other headers from `authkit()` (including future `x-workos-*` headers) are filtered out for security.\n\n## Usage\n\n### Wrap your app in `AuthKitProvider`\n\nUse `AuthKitProvider` to wrap your app layout, which provides client side auth methods adds protections for auth edge cases.\n\n```jsx\nimport { AuthKitProvider } from '@workos-inc/authkit-nextjs/components';\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    \u003chtml lang=\"en\"\u003e\n      \u003cbody\u003e\n        \u003cAuthKitProvider\u003e{children}\u003c/AuthKitProvider\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n  );\n}\n```\n\n#### Optimizing with Server-Side Auth Data\n\nTo avoid a server action call on mount, you can pass the initial auth data from the server to the `AuthKitProvider`.\n\n```jsx\nimport { AuthKitProvider } from '@workos-inc/authkit-nextjs/components';\nimport { withAuth } from '@workos-inc/authkit-nextjs';\n\nexport default async function RootLayout({ children }: { children: React.ReactNode }) {\n  // Fetch auth data on the server\n  const auth = await withAuth();\n\n  // Remove the accessToken from the auth object as it is not needed on the client side\n  const { accessToken, ...initialAuth } = auth;\n\n  return (\n    \u003chtml lang=\"en\"\u003e\n      \u003cbody\u003e\n        \u003cAuthKitProvider initialAuth={initialAuth}\u003e{children}\u003c/AuthKitProvider\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n  );\n}\n```\n\n### Get the current user in a server component\n\nFor pages where you want to display a signed-in and signed-out view, use `withAuth` to retrieve the user session from WorkOS.\n\n```jsx\nimport Link from 'next/link';\nimport { getSignInUrl, getSignUpUrl, withAuth, signOut } from '@workos-inc/authkit-nextjs';\n\nexport default async function HomePage() {\n  // Retrieves the user from the session or returns `null` if no user is signed in\n  const { user } = await withAuth();\n\n  if (!user) {\n    // Get the URL to redirect the user to AuthKit to sign in\n    const signInUrl = await getSignInUrl();\n\n    // Get the URL to redirect the user to AuthKit to sign up\n    const signUpUrl = await getSignUpUrl();\n\n    // You can also pass custom state data through the auth flow\n    const signInUrlWithState = await getSignInUrl({\n      state: JSON.stringify({\n        teamId: 'team_123',\n        referrer: 'homepage',\n      }),\n    });\n\n    return (\n      \u003c\u003e\n        \u003cLink href={signInUrl}\u003eLog in\u003c/Link\u003e\n        \u003cLink href={signUpUrl}\u003eSign Up\u003c/Link\u003e\n      \u003c/\u003e\n    );\n  }\n\n  return (\n    \u003cform\n      action={async () =\u003e {\n        'use server';\n        await signOut();\n      }}\n    \u003e\n      \u003cp\u003eWelcome back {user?.firstName \u0026\u0026 `, ${user?.firstName}`}\u003c/p\u003e\n      \u003cbutton type=\"submit\"\u003eSign out\u003c/button\u003e\n    \u003c/form\u003e\n  );\n}\n```\n\n### Get the current user in a client component\n\nFor client components, use the `useAuth` hook to get the current user session.\n\n```jsx\n'use client';\n// Note the updated import path\nimport { useAuth } from '@workos-inc/authkit-nextjs/components';\n\nexport default function MyComponent() {\n  // Retrieves the user from the session or returns `null` if no user is signed in\n  const { user, loading } = useAuth();\n\n  if (loading) {\n    return \u003cdiv\u003eLoading...\u003c/div\u003e;\n  }\n\n  return \u003cdiv\u003e{user?.firstName}\u003c/div\u003e;\n}\n```\n\n### Get the enabled flags for the logged in user\n\nFor situations where you need access to the authenticated user's currently active feature flags, use `withAuth` to retrieve the flags from the WorkOS session.\n\n```jsx\nconst { featureFlags } = await withAuth();\n```\n\n### Requiring auth\n\nFor pages where a signed-in user is mandatory, you can use the `ensureSignedIn` option:\n\n```jsx\n// Server component\nconst { user } = await withAuth({ ensureSignedIn: true });\n\n// Client component\nconst { user, loading } = useAuth({ ensureSignedIn: true });\n```\n\nEnabling `ensureSignedIn` will redirect users to AuthKit if they attempt to access the page without being authenticated.\n\n### Refreshing the session\n\nUse the `refreshSession` method in a server action or route handler to fetch the latest session details, including any changes to the user's roles or permissions.\n\nThe `organizationId` parameter can be passed to `refreshSession` in order to switch the session to a different organization. If the current session is not authorized for the next organization, an appropriate [authentication error](https://workos.com/docs/reference/user-management/authentication-errors) will be returned.\n\nIn client components, you can refresh the session with the `refreshAuth` hook.\n\n```tsx\n'use client';\n\nimport { useAuth } from '@workos-inc/authkit-nextjs/components';\nimport React, { useEffect } from 'react';\n\nexport function SwitchOrganizationButton() {\n  const { user, organizationId, loading, refreshAuth } = useAuth();\n\n  useEffect(() =\u003e {\n    // This will log out the new organizationId after refreshing the session\n    console.log('organizationId', organizationId);\n  }, [organizationId]);\n\n  if (loading) {\n    return \u003cdiv\u003eLoading...\u003c/div\u003e;\n  }\n\n  const handleRefreshSession = async () =\u003e {\n    const result = await refreshAuth({\n      // Provide the organizationId to switch to\n      organizationId: 'org_123',\n    });\n    if (result?.error) {\n      console.log('Error refreshing session:', result.error);\n    }\n  };\n\n  if (user) {\n    return \u003cbutton onClick={handleRefreshSession}\u003eRefresh session\u003c/button\u003e;\n  } else {\n    return \u003cdiv\u003eNot signed in\u003c/div\u003e;\n  }\n}\n```\n\n### Access Token Management\n\n#### useAccessToken Hook\n\nThis library provides a `useAccessToken` hook for client-side access token management with automatic refresh functionality.\n\n##### Features\n\n- Automatic token refresh before expiration\n- Manual refresh capability\n- Loading and error states\n- Synchronized with the main authentication session\n- Race condition prevention\n\n##### When to Use\n\nUse this hook when you need direct access to the JWT token for:\n\n- Making authenticated API calls\n- Setting up external auth-dependent libraries\n- Implementing custom authentication logic\n\n##### Basic Usage\n\n```jsx\nfunction ApiClient() {\n  const { accessToken, loading, error, refresh } = useAccessToken();\n\n  if (loading) return \u003cdiv\u003eLoading...\u003c/div\u003e;\n  if (error) return \u003cdiv\u003eError: {error.message}\u003c/div\u003e;\n  if (!accessToken) return \u003cdiv\u003eNot authenticated\u003c/div\u003e;\n\n  return (\n    \u003cdiv\u003e\n      \u003cp\u003eToken available: {accessToken.substring(0, 10)}...\u003c/p\u003e\n      \u003cbutton onClick={refresh}\u003eRefresh token\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n##### API Reference\n\n| Property      | Type                                 | Description                                   |\n| ------------- | ------------------------------------ | --------------------------------------------- |\n| `accessToken` | `string \\| undefined`                | The current access token                      |\n| `loading`     | `boolean`                            | True when token is being fetched or refreshed |\n| `error`       | `Error \\| null`                      | Error during token fetch/refresh, or null     |\n| `refresh`     | `() =\u003e Promise\u003cstring \\| undefined\u003e` | Manually refresh the token                    |\n\n##### Integration with useAuth\n\nThe `useAccessToken` hook automatically synchronizes with the main authentication session. When you call `refreshAuth()` from `useAuth`, the access token will update accordingly. Similarly, using the `refresh()` method from `useAccessToken` will update the entire authentication session.\n\n##### Security Considerations\n\nJWT tokens are sensitive credentials and should be handled carefully:\n\n- Only use the token where necessary\n- Don't store tokens in localStorage or sessionStorage\n- Be cautious about exposing tokens in your application state\n\n### Passing Custom State Through Authentication\n\nYou can pass custom state data through the authentication flow using the `state` parameter. The state parameter is a string value that gets passed through OAuth and returned in the callback. To pass complex data, serialize it as JSON:\n\n```ts\n// When generating sign-in/sign-up URLs, serialize your data as JSON\nconst signInUrl = await getSignInUrl({\n  state: JSON.stringify({\n    teamId: 'team_123',\n    feature: 'billing',\n    referrer: 'pricing-page',\n    timestamp: Date.now(),\n  }),\n});\n\n// The state data is available in the callback handler\nexport const GET = handleAuth({\n  onSuccess: async ({ user, state }) =\u003e {\n    // Parse the state string back to an object\n    const customData = state ? JSON.parse(state) : null;\n\n    // Access your custom state data\n    if (customData?.teamId) {\n      await addUserToTeam(user.id, customData.teamId);\n    }\n\n    if (customData?.feature) {\n      await trackFeatureActivation(user.id, customData.feature);\n    }\n\n    // Track where the user came from\n    await analytics.track('sign_in_completed', {\n      userId: user.id,\n      referrer: customData?.referrer,\n      timestamp: customData?.timestamp,\n    });\n  },\n});\n```\n\n\u003e **Note**: The `state` parameter is an opaque string as defined by OAuth 2.0 (RFC 6749). If you need to pass structured data, you must serialize it yourself using `JSON.stringify()` and parse it with `JSON.parse()` in the callback.\n\nThis is useful for:\n\n- Tracking user journey and referral sources\n- Maintaining context about what the user was trying to do before authentication\n- Implementing custom onboarding flows\n- Analytics and attribution tracking\n\n### Session Refresh Callbacks\n\nWhen using the `authkit` function directly, you can provide callbacks to be notified when a session is refreshed:\n\n```typescript\nconst { session, headers } = await authkit(request, {\n  onSessionRefreshSuccess: async ({ accessToken, user, impersonator }) =\u003e {\n    // Log successful refresh\n    console.log(`Session refreshed for ${user.email}.`);\n  },\n  onSessionRefreshError: async ({ error, request }) =\u003e {\n    // Log refresh failure\n    console.error('Session refresh failed:', error);\n    // Notify monitoring system\n    await notifyMonitoring('session_refresh_failed', {\n      url: request.url,\n      error: error.message,\n    });\n  },\n});\n```\n\nThese callbacks provide a way to perform side effects when sessions are refreshed in the proxy/middleware. Common use cases include:\n\n- Logging authentication events\n- Updating last activity timestamps\n- Triggering organization-specific data prefetching\n- Recording failed refresh attempts\n\n### Proxy / Middleware auth\n\nThe default behavior of this library is to request authentication via the `withAuth` method on a per-page basis. There are some use cases where you don't want to call `withAuth` (e.g. you don't need user data for your page) or if you'd prefer a \"secure by default\" approach where every route defined in your proxy/middleware matcher is protected unless specified otherwise. In those cases you can opt-in to use `middlewareAuth` instead:\n\n```ts\nimport { authkitMiddleware } from '@workos-inc/authkit-nextjs';\n\nexport default authkitMiddleware({\n  middlewareAuth: {\n    enabled: true,\n    unauthenticatedPaths: ['/', '/about'],\n  },\n});\n\n// Match against pages that require auth\n// Leave this out if you want auth on every resource (including images, css etc.)\nexport const config = { matcher: ['/', '/admin/:path*', '/about'] };\n```\n\nIn the above example the `/admin` page will require a user to be signed in, whereas `/` and `/about` can be accessed without signing in.\n\n`unauthenticatedPaths` uses the same glob logic as the [Next.js matcher](https://nextjs.org/docs/pages/building-your-application/routing/middleware#matcher).\n\n### Eager auth\n\nThe `eagerAuth` option enables synchronous access to authentication tokens on initial page load, which is required by some third-party services that validate tokens directly with WorkOS. When enabled, tokens are available immediately without requiring an asynchronous fetch.\n\n#### How it works\n\nWhen `eagerAuth: true` is set, the proxy/middleware temporarily stores the access token in a short-lived cookie (30 seconds) that is:\n\n- Only set on initial page loads (not API or prefetch requests)\n- Immediately consumed and deleted by the client\n- Available synchronously on the first render\n\n#### Usage\n\nEnable eager auth in your proxy/middleware configuration:\n\n```ts\nimport { authkitMiddleware } from '@workos-inc/authkit-nextjs';\n\nexport default authkitMiddleware({\n  eagerAuth: true,\n});\n```\n\nThen access the token synchronously in your client components:\n\n```tsx\n'use client';\n\nimport { useAccessToken } from '@workos-inc/authkit-nextjs/components';\n\nfunction MyComponent() {\n  const { getAccessToken } = useAccessToken();\n\n  // Token is available immediately on initial page load\n  const token = getAccessToken();\n\n  // Use with third-party services that need immediate token access\n  if (token) {\n    // Initialize your third-party client with the token\n    thirdPartyClient.authenticate(token);\n  }\n\n  return \u003cdiv\u003e...\u003c/div\u003e;\n}\n```\n\n#### Security considerations\n\nEager auth makes tokens briefly accessible via JavaScript (30-second window) to enable synchronous access. This is a common pattern used by many authentication libraries and is generally safe with standard XSS protections.\n\n**Best practices:**\n\n- Implement a Content Security Policy (CSP) if handling sensitive data\n- Review third-party scripts on authenticated pages\n- Use the standard `getAccessToken()` method when synchronous access isn't required\n\n**When to use:**\n\n- Third-party services that require synchronous token access\n- Real-time features that need immediate authentication\n- When you want to avoid loading states on initial render\n\n**When to use standard async tokens:**\n\n- Most API calls where a brief loading state is acceptable\n- When you don't need immediate token access on page load\n\n### Signing out\n\nUse the `signOut` method to sign out the current logged in user and redirect to your app's default Logout URI. The Logout URI is set in your WorkOS dashboard settings under \"Redirect\".\n\nTo use a non-default Logout URI, you can use the `returnTo` parameter.\n\n```tsx\nawait signOut({ returnTo: 'https://your-app.com/signed-out' });\n```\n\n### Visualizing an impersonation\n\nRender the `Impersonation` component in your app so that it is clear when someone is [impersonating a user](https://workos.com/docs/user-management/impersonation).\nThe component will display a frame with some information about the impersonated user, as well as a button to stop impersonating.\n\n```jsx\nimport { Impersonation, AuthKitProvider } from '@workos-inc/authkit-nextjs/components';\n\nexport default function App() {\n  return (\n    \u003cdiv\u003e\n      \u003cAuthKitProvider\u003e\n        \u003cImpersonation /\u003e\n        {/* Your app content */}\n      \u003c/AuthKitProvider\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Get the access token\n\nSometimes it is useful to obtain the access token directly, for instance to make API requests to another service.\n\n```jsx\nimport { withAuth } from '@workos-inc/authkit-nextjs';\n\nexport default async function HomePage() {\n  const { accessToken } = await withAuth();\n\n  if (!accessToken) {\n    return \u003cdiv\u003eNot signed in\u003c/div\u003e;\n  }\n\n  const serviceData = await fetch('/api/path', {\n    headers: {\n      Authorization: `Bearer ${accessToken}`,\n    },\n  });\n\n  return \u003cdiv\u003e{serviceData}\u003c/div\u003e;\n}\n```\n\n### Sign up paths\n\nThe `signUpPaths` option can be passed to `authkitMiddleware` to specify paths that should use the 'sign-up' screen hint when redirecting to AuthKit. This is useful for cases where you want a path that mandates authentication to be treated as a sign up page.\n\n```ts\nimport { authkitMiddleware } from '@workos-inc/authkit-nextjs';\n\nexport default authkitMiddleware({\n  signUpPaths: ['/account/sign-up', '/dashboard/:path*'],\n});\n```\n\n### Validate an API key\n\nUse the `validateApiKey` function in your application's public API endpoints to parse a [Bearer Authentication](https://swagger.io/docs/specification/v3_0/authentication/bearer-authentication/) header and validate the [API key](https://workos.com/docs/authkit/api-keys) with WorkOS.\n\n```ts\nimport { NextResponse } from 'next/server';\nimport { validateApiKey } from '@workos-inc/authkit-nextjs';\n\nexport async function GET() {\n  const { apiKey } = await validateApiKey();\n\n  if (!apiKey) {\n    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n  }\n\n  return NextResponse.json({ success: true });\n}\n```\n\n### Advanced: Direct access to the WorkOS client\n\nFor advanced use cases or functionality not covered by the helper methods, you can access the underlying WorkOS client directly:\n\n```typescript\nimport { getWorkOS } from '@workos-inc/authkit-nextjs';\n\n// Get the configured WorkOS client instance\nconst workos = getWorkOS();\n\n// Use any WorkOS SDK method\nconst organizations = await workos.organizations.listOrganizations({\n  limit: 10,\n});\n```\n\n### Advanced: Custom authentication flows\n\nWhile the standard authentication flow handles session management automatically, some use cases require manually creating and storing a session. This is useful for custom authentication flows like email verification or token exchange.\n\nFor these scenarios, you can use the `saveSession` function:\n\n```typescript\nimport { saveSession } from '@workos-inc/authkit-nextjs';\nimport { getWorkOS } from '@workos-inc/authkit-nextjs';\n\n// Example: Email verification flow\nasync function handleEmailVerification(req) {\n  const { code } = await req.json();\n\n  // Authenticate with the WorkOS API directly\n  const authResponse = await getWorkOS().userManagement.authenticateWithEmailVerification({\n    clientId: process.env.WORKOS_CLIENT_ID,\n    code,\n  });\n\n  // Save the session data to a cookie\n  await saveSession(\n    {\n      accessToken: authResponse.accessToken,\n      refreshToken: authResponse.refreshToken,\n      user: authResponse.user,\n      impersonator: authResponse.impersonator,\n    },\n    req,\n  );\n\n  return Response.redirect('/dashboard');\n}\n```\n\n\u003e [!NOTE]\n\u003e This is an advanced API intended for specific integration scenarios, such as those users using self-hosted AuthKit. If you're using hosted AuthKit you should not need this.\n\nThe `saveSession` function accepts either a `NextRequest` object or a URL string as its second parameter.\n\n```typescript\n// With NextRequest\nawait saveSession(session, req);\n\n// With URL string\nawait saveSession(session, 'https://example.com/callback');\n```\n\n### CDN Deployments and Caching\n\nAuthKit automatically implements cache security measures to protect against session leakage in CDN environments. This is particularly important when deploying to AWS with SST/OpenNext, Cloudflare, or other CDN configurations.\n\n#### How It Works\n\nThe library automatically sets appropriate cache headers on all authenticated requests:\n\n- `Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0` - Aggressive cache prevention with multiple directives\n- `Pragma: no-cache` - HTTP/1.0 compatibility\n- `Expires: 0` - HTTP/1.0 cache expiration\n- `Vary: Cookie` - Ensures CDNs differentiate between different users (defense-in-depth)\n- `x-middleware-cache: no-cache` - Prevents Next.js proxy/middleware result caching\n\nThese headers are applied automatically when:\n\n- A session cookie is present in the request\n- An Authorization header is detected\n- An active authenticated session exists\n\n#### Performance Considerations\n\n**Authenticated pages:** Will not be cached at the CDN level and will always hit your origin server. This is the correct and secure behavior for session-based authentication.\n\n**Public pages:** Unaffected by these security measures. Public routes without authentication context can still be cached normally.\n\n### Debugging\n\nTo enable debug logs, initialize the proxy/middleware with the debug flag enabled.\n\n```js\nimport { authkitMiddleware } from '@workos-inc/authkit-nextjs';\n\nexport default authkitMiddleware({ debug: true });\n```\n\n### Troubleshooting\n\n#### NEXT_REDIRECT error when using try/catch blocks\n\nWrapping a `withAuth({ ensureSignedIn: true })` call in a try/catch block will cause a `NEXT_REDIRECT` error. This is because `withAuth` will attempt to redirect the user to AuthKit if no session is detected and redirects in Next must be [called outside a try/catch](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#redirecting).\n\n#### Module build failed: UnhandledSchemeError: Reading from \"node:crypto\" is not handled by plugins (Unhandled scheme)\n\nYou may encounter this error if you attempt to import server side code from authkit-nextjs into a client component. Likely you are using `withAuth` in a client component instead of the `useAuth` hook. Either move the code to a server component or use the `useAuth` hook.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkos%2Fauthkit-nextjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fworkos%2Fauthkit-nextjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkos%2Fauthkit-nextjs/lists"}