@workos-inc/authkit-nextjs 2.9.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -94,11 +94,15 @@ If your application needs to persist data upon a successful authentication, like
94
94
 
95
95
  ```ts
96
96
  export const GET = handleAuth({
97
- onSuccess: async ({ user, oauthTokens, authenticationMethod, organizationId }) => {
97
+ onSuccess: async ({ user, oauthTokens, authenticationMethod, organizationId, state }) => {
98
98
  await saveTokens(oauthTokens);
99
99
  if (authenticationMethod) {
100
100
  await saveAuthMethod(user.id, authenticationMethod);
101
101
  }
102
+ // Access custom state data passed through the auth flow
103
+ if (state?.teamId) {
104
+ await addUserToTeam(user.id, state.teamId);
105
+ }
102
106
  },
103
107
  });
104
108
  ```
@@ -124,15 +128,16 @@ export const GET = handleAuth({
124
128
 
125
129
  The `onSuccess` callback receives the following data:
126
130
 
127
- | Property | Type | Description |
128
- | ---------------------- | --------------------------- | -------------------------------------------------------------------------------------------------- |
129
- | `user` | `User` | The authenticated user object |
130
- | `accessToken` | `string` | JWT access token |
131
- | `refreshToken` | `string` | Refresh token for session renewal |
132
- | `impersonator` | `Impersonator \| undefined` | Present if user is being impersonated |
133
- | `oauthTokens` | `OauthTokens \| undefined` | OAuth tokens from upstream provider |
134
- | `authenticationMethod` | `string \| undefined` | How the user authenticated (e.g., 'password', 'google-oauth'). Only available during initial login |
135
- | `organizationId` | `string \| undefined` | Organization context of authentication |
131
+ | Property | Type | Description |
132
+ | ---------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------- |
133
+ | `user` | `User` | The authenticated user object |
134
+ | `accessToken` | `string` | JWT access token |
135
+ | `refreshToken` | `string` | Refresh token for session renewal |
136
+ | `impersonator` | `Impersonator \| undefined` | Present if user is being impersonated |
137
+ | `oauthTokens` | `OauthTokens \| undefined` | OAuth tokens from upstream provider |
138
+ | `authenticationMethod` | `string \| undefined` | How the user authenticated (e.g., 'password', 'google-oauth'). Only available during initial login |
139
+ | `organizationId` | `string \| undefined` | Organization context of authentication |
140
+ | `state` | `Record<string, any> \| undefined` | Custom state data passed through the authentication flow |
136
141
 
137
142
  **Note**: `authenticationMethod` is only provided during the initial authentication callback. It will not be available in subsequent requests or session refreshes.
138
143
 
@@ -217,6 +222,14 @@ export default async function HomePage() {
217
222
  // Get the URL to redirect the user to AuthKit to sign up
218
223
  const signUpUrl = await getSignUpUrl();
219
224
 
225
+ // You can also pass custom state data through the auth flow
226
+ const signInUrlWithState = await getSignInUrl({
227
+ state: {
228
+ teamId: 'team_123',
229
+ referrer: 'homepage',
230
+ },
231
+ });
232
+
220
233
  return (
221
234
  <>
222
235
  <Link href={signInUrl}>Log in</Link>
@@ -244,7 +257,7 @@ export default async function HomePage() {
244
257
  For client components, use the `useAuth` hook to get the current user session.
245
258
 
246
259
  ```jsx
247
- 'use client'
260
+ 'use client';
248
261
  // Note the updated import path
249
262
  import { useAuth } from '@workos-inc/authkit-nextjs/components';
250
263
 
@@ -260,6 +273,14 @@ export default function MyComponent() {
260
273
  }
261
274
  ```
262
275
 
276
+ ### Get the enabled flags for the logged in user
277
+
278
+ For situations where you need access to the authenticated user's currently active feature flags, use `withAuth` to retrieve the flags from the WorkOS session.
279
+
280
+ ```jsx
281
+ const { featureFlags } = await withAuth();
282
+ ```
283
+
263
284
  ### Requiring auth
264
285
 
265
286
  For pages where a signed-in user is mandatory, you can use the `ensureSignedIn` option:
@@ -380,6 +401,50 @@ JWT tokens are sensitive credentials and should be handled carefully:
380
401
  - Don't store tokens in localStorage or sessionStorage
381
402
  - Be cautious about exposing tokens in your application state
382
403
 
404
+ ### Passing Custom State Through Authentication
405
+
406
+ You can pass custom state data through the authentication flow using the `state` parameter. This data will be available in the `onSuccess` callback after authentication:
407
+
408
+ ```ts
409
+ // When generating sign-in/sign-up URLs
410
+ const signInUrl = await getSignInUrl({
411
+ state: {
412
+ teamId: 'team_123',
413
+ feature: 'billing',
414
+ referrer: 'pricing-page',
415
+ timestamp: Date.now(),
416
+ },
417
+ });
418
+
419
+ // The state data is available in the callback handler
420
+ export const GET = handleAuth({
421
+ onSuccess: async ({ user, state }) => {
422
+ // Access your custom state data
423
+ if (state?.teamId) {
424
+ await addUserToTeam(user.id, state.teamId);
425
+ }
426
+
427
+ if (state?.feature) {
428
+ await trackFeatureActivation(user.id, state.feature);
429
+ }
430
+
431
+ // Track where the user came from
432
+ await analytics.track('sign_in_completed', {
433
+ userId: user.id,
434
+ referrer: state?.referrer,
435
+ timestamp: state?.timestamp,
436
+ });
437
+ },
438
+ });
439
+ ```
440
+
441
+ This is useful for:
442
+
443
+ - Tracking user journey and referral sources
444
+ - Maintaining context about what the user was trying to do before authentication
445
+ - Implementing custom onboarding flows
446
+ - Analytics and attribution tracking
447
+
383
448
  ### Session Refresh Callbacks
384
449
 
385
450
  When using the `authkit` function directly, you can provide callbacks to be notified when a session is refreshed:
@@ -461,10 +526,10 @@ Then access the token synchronously in your client components:
461
526
  ```tsx
462
527
  'use client';
463
528
 
464
- import { useAuth } from '@workos-inc/authkit-nextjs';
529
+ import { useAccessToken } from '@workos-inc/authkit-nextjs/components';
465
530
 
466
531
  function MyComponent() {
467
- const { getAccessToken } = useAuth();
532
+ const { getAccessToken } = useAccessToken();
468
533
 
469
534
  // Token is available immediately on initial page load
470
535
  const token = getAccessToken();
@@ -704,6 +769,6 @@ export default authkitMiddleware({ debug: true });
704
769
 
705
770
  Wrapping 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).
706
771
 
707
- #### Module build failed: UnhandledSchemeError: Reading from "node:crypto" is not handled by plugins (Unhandled scheme).
772
+ #### Module build failed: UnhandledSchemeError: Reading from "node:crypto" is not handled by plugins (Unhandled scheme)
708
773
 
709
774
  You 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.
package/dist/esm/auth.js CHANGED
@@ -8,11 +8,11 @@ import { getCookieOptions } from './cookie.js';
8
8
  import { getAuthorizationUrl } from './get-authorization-url.js';
9
9
  import { getSessionFromCookie, refreshSession, withAuth } from './session.js';
10
10
  import { getWorkOS } from './workos.js';
11
- export async function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, } = {}) {
12
- return getAuthorizationUrl({ organizationId, screenHint: 'sign-in', loginHint, redirectUri, prompt });
11
+ export async function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, state, } = {}) {
12
+ return getAuthorizationUrl({ organizationId, screenHint: 'sign-in', loginHint, redirectUri, prompt, state });
13
13
  }
14
- export async function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, } = {}) {
15
- return getAuthorizationUrl({ organizationId, screenHint: 'sign-up', loginHint, redirectUri, prompt });
14
+ export async function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, state, } = {}) {
15
+ return getAuthorizationUrl({ organizationId, screenHint: 'sign-up', loginHint, redirectUri, prompt, state });
16
16
  }
17
17
  /**
18
18
  * Sign out the user and delete the session cookie.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,40 @@ import { WORKOS_CLIENT_ID } from './env-variables.js';
2
2
  import { saveSession } from './session.js';
3
3
  import { errorResponseWithFallback, redirectWithFallback } from './utils.js';
4
4
  import { getWorkOS } from './workos.js';
5
+ function handleState(state) {
6
+ let returnPathname = undefined;
7
+ let userState;
8
+ if (state === null || state === void 0 ? void 0 : state.includes('.')) {
9
+ const [internal, ...rest] = state.split('.');
10
+ userState = rest.join('.');
11
+ try {
12
+ // Reverse URL-safe base64 encoding
13
+ const decoded = internal.replace(/-/g, '+').replace(/_/g, '/');
14
+ returnPathname = JSON.parse(atob(decoded)).returnPathname;
15
+ }
16
+ catch (_a) {
17
+ // Malformed internal part, ignore it
18
+ }
19
+ }
20
+ else if (state) {
21
+ try {
22
+ const decoded = JSON.parse(atob(state));
23
+ if (decoded.returnPathname) {
24
+ returnPathname = decoded.returnPathname;
25
+ }
26
+ else {
27
+ userState = state;
28
+ }
29
+ }
30
+ catch (_b) {
31
+ userState = state;
32
+ }
33
+ }
34
+ return {
35
+ returnPathname,
36
+ state: userState,
37
+ };
38
+ }
5
39
  export function handleAuth(options = {}) {
6
40
  const { returnPathname: returnPathnameOption = '/', baseURL, onSuccess, onError } = options;
7
41
  // Throw early if baseURL is provided but invalid
@@ -16,7 +50,7 @@ export function handleAuth(options = {}) {
16
50
  return async function GET(request) {
17
51
  const code = request.nextUrl.searchParams.get('code');
18
52
  const state = request.nextUrl.searchParams.get('state');
19
- let returnPathname = state && state !== 'null' ? JSON.parse(atob(state)).returnPathname : null;
53
+ const { state: customState, returnPathname: returnPathnameState } = handleState(state);
20
54
  if (code) {
21
55
  try {
22
56
  // Use the code returned to us by AuthKit and authenticate the user with WorkOS
@@ -32,7 +66,7 @@ export function handleAuth(options = {}) {
32
66
  url.searchParams.delete('code');
33
67
  url.searchParams.delete('state');
34
68
  // Redirect to the requested path and store the session
35
- returnPathname = returnPathname !== null && returnPathname !== void 0 ? returnPathname : returnPathnameOption;
69
+ const returnPathname = returnPathnameState !== null && returnPathnameState !== void 0 ? returnPathnameState : returnPathnameOption;
36
70
  // Extract the search params if they are present
37
71
  if (returnPathname.includes('?')) {
38
72
  const newUrl = new URL(returnPathname, 'https://example.com');
@@ -59,6 +93,7 @@ export function handleAuth(options = {}) {
59
93
  oauthTokens,
60
94
  authenticationMethod,
61
95
  organizationId,
96
+ state: customState,
62
97
  });
63
98
  }
64
99
  return response;
@@ -1 +1 @@
1
- {"version":3,"file":"authkit-callback-route.js","sourceRoot":"","sources":["../../src/authkit-callback-route.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"authkit-callback-route.js","sourceRoot":"","sources":["../../src/authkit-callback-route.ts"],"names":[],"mappings":"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"}
@@ -3,12 +3,16 @@ import { WORKOS_CLIENT_ID, WORKOS_REDIRECT_URI } from './env-variables.js';
3
3
  import { headers } from 'next/headers';
4
4
  async function getAuthorizationUrl(options = {}) {
5
5
  const headersList = await headers();
6
- const { returnPathname, screenHint, organizationId, redirectUri = headersList.get('x-redirect-uri'), loginHint, prompt, } = options;
6
+ const { returnPathname, screenHint, organizationId, redirectUri = headersList.get('x-redirect-uri'), loginHint, prompt, state: customState, } = options;
7
+ const internalState = returnPathname
8
+ ? btoa(JSON.stringify({ returnPathname })).replace(/\+/g, '-').replace(/\//g, '_')
9
+ : null;
10
+ const finalState = internalState && customState ? `${internalState}.${customState}` : internalState || customState || undefined;
7
11
  return getWorkOS().userManagement.getAuthorizationUrl({
8
12
  provider: 'authkit',
9
13
  clientId: WORKOS_CLIENT_ID,
10
14
  redirectUri: redirectUri !== null && redirectUri !== void 0 ? redirectUri : WORKOS_REDIRECT_URI,
11
- state: returnPathname ? btoa(JSON.stringify({ returnPathname })) : undefined,
15
+ state: finalState,
12
16
  screenHint,
13
17
  organizationId,
14
18
  loginHint,
@@ -1 +1 @@
1
- {"version":3,"file":"get-authorization-url.js","sourceRoot":"","sources":["../../src/get-authorization-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,KAAK,UAAU,mBAAmB,CAAC,UAA6B,EAAE;IAChE,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;IACpC,MAAM,EACJ,cAAc,EACd,UAAU,EACV,cAAc,EACd,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAC/C,SAAS,EACT,MAAM,GACP,GAAG,OAAO,CAAC;IAEZ,OAAO,SAAS,EAAE,CAAC,cAAc,CAAC,mBAAmB,CAAC;QACpD,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,gBAAgB;QAC1B,WAAW,EAAE,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,mBAAmB;QAC/C,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QAC5E,UAAU;QACV,cAAc;QACd,SAAS;QACT,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
1
+ {"version":3,"file":"get-authorization-url.js","sourceRoot":"","sources":["../../src/get-authorization-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,KAAK,UAAU,mBAAmB,CAAC,UAA6B,EAAE;IAChE,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;IACpC,MAAM,EACJ,cAAc,EACd,UAAU,EACV,cAAc,EACd,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAC/C,SAAS,EACT,MAAM,EACN,KAAK,EAAE,WAAW,GACnB,GAAG,OAAO,CAAC;IAEZ,MAAM,aAAa,GAAG,cAAc;QAClC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;QAClF,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,UAAU,GACd,aAAa,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,aAAa,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,aAAa,IAAI,WAAW,IAAI,SAAS,CAAC;IAE/G,OAAO,SAAS,EAAE,CAAC,cAAc,CAAC,mBAAmB,CAAC;QACpD,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,gBAAgB;QAC1B,WAAW,EAAE,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,mBAAmB;QAC/C,KAAK,EAAE,UAAU;QACjB,UAAU;QACV,cAAc;QACd,SAAS;QACT,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -1,15 +1,17 @@
1
1
  import type { SwitchToOrganizationOptions, UserInfo } from './interfaces.js';
2
- export declare function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, }?: {
2
+ export declare function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, state, }?: {
3
3
  organizationId?: string;
4
4
  loginHint?: string;
5
5
  redirectUri?: string;
6
6
  prompt?: 'consent';
7
+ state?: string;
7
8
  }): Promise<string>;
8
- export declare function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, }?: {
9
+ export declare function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, state, }?: {
9
10
  organizationId?: string;
10
11
  loginHint?: string;
11
12
  redirectUri?: string;
12
13
  prompt?: 'consent';
14
+ state?: string;
13
15
  }): Promise<string>;
14
16
  /**
15
17
  * Sign out the user and delete the session cookie.
@@ -13,6 +13,7 @@ export interface HandleAuthSuccessData extends Session {
13
13
  oauthTokens?: OauthTokens;
14
14
  organizationId?: string;
15
15
  authenticationMethod?: AuthenticationResponse['authenticationMethod'];
16
+ state?: string | undefined;
16
17
  }
17
18
  export interface Impersonator {
18
19
  email: string;
@@ -64,6 +65,7 @@ export interface GetAuthURLOptions {
64
65
  redirectUri?: string;
65
66
  loginHint?: string;
66
67
  prompt?: 'consent';
68
+ state?: string;
67
69
  }
68
70
  export interface AuthkitMiddlewareAuth {
69
71
  enabled: boolean;
@@ -1,5 +1,5 @@
1
1
  import { WorkOS } from '@workos-inc/node';
2
- export declare const VERSION = "2.9.0";
2
+ export declare const VERSION = "2.10.0";
3
3
  /**
4
4
  * Create a WorkOS instance with the provided API key and options.
5
5
  * If an instance already exists, it returns the existing instance.
@@ -1,7 +1,7 @@
1
1
  import { WorkOS } from '@workos-inc/node';
2
2
  import { WORKOS_API_HOSTNAME, WORKOS_API_KEY, WORKOS_API_HTTPS, WORKOS_API_PORT } from './env-variables.js';
3
3
  import { lazy } from './utils.js';
4
- export const VERSION = '2.9.0';
4
+ export const VERSION = '2.10.0';
5
5
  const options = {
6
6
  apiHostname: WORKOS_API_HOSTNAME,
7
7
  https: WORKOS_API_HTTPS ? WORKOS_API_HTTPS === 'true' : true,
@@ -1 +1 @@
1
- {"version":3,"file":"workos.js","sourceRoot":"","sources":["../../src/workos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC5G,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,MAAM,OAAO,GAAG;IACd,WAAW,EAAE,mBAAmB;IAChC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI;IAC5D,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS;IAC7D,OAAO,EAAE;QACP,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,OAAO;KACjB;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"workos.js","sourceRoot":"","sources":["../../src/workos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC5G,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC;AAEhC,MAAM,OAAO,GAAG;IACd,WAAW,EAAE,mBAAmB;IAChC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI;IAC5D,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS;IAC7D,OAAO,EAAE;QACP,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,OAAO;KACjB;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos-inc/authkit-nextjs",
3
- "version": "2.9.0",
3
+ "version": "2.10.0",
4
4
  "description": "Authentication and session helpers for using WorkOS & AuthKit with Next.js",
5
5
  "sideEffects": false,
6
6
  "type": "module",
package/src/auth.ts CHANGED
@@ -15,8 +15,15 @@ export async function getSignInUrl({
15
15
  loginHint,
16
16
  redirectUri,
17
17
  prompt,
18
- }: { organizationId?: string; loginHint?: string; redirectUri?: string; prompt?: 'consent' } = {}) {
19
- return getAuthorizationUrl({ organizationId, screenHint: 'sign-in', loginHint, redirectUri, prompt });
18
+ state,
19
+ }: {
20
+ organizationId?: string;
21
+ loginHint?: string;
22
+ redirectUri?: string;
23
+ prompt?: 'consent';
24
+ state?: string;
25
+ } = {}) {
26
+ return getAuthorizationUrl({ organizationId, screenHint: 'sign-in', loginHint, redirectUri, prompt, state });
20
27
  }
21
28
 
22
29
  export async function getSignUpUrl({
@@ -24,8 +31,15 @@ export async function getSignUpUrl({
24
31
  loginHint,
25
32
  redirectUri,
26
33
  prompt,
27
- }: { organizationId?: string; loginHint?: string; redirectUri?: string; prompt?: 'consent' } = {}) {
28
- return getAuthorizationUrl({ organizationId, screenHint: 'sign-up', loginHint, redirectUri, prompt });
34
+ state,
35
+ }: {
36
+ organizationId?: string;
37
+ loginHint?: string;
38
+ redirectUri?: string;
39
+ prompt?: 'consent';
40
+ state?: string;
41
+ } = {}) {
42
+ return getAuthorizationUrl({ organizationId, screenHint: 'sign-up', loginHint, redirectUri, prompt, state });
29
43
  }
30
44
 
31
45
  /**
@@ -275,5 +275,73 @@ describe('authkit-callback-route', () => {
275
275
  const session = await getSessionFromCookie();
276
276
  expect(session?.accessToken).toBe(newAccessToken);
277
277
  });
278
+
279
+ it('should pass custom state data to onSuccess callback', async () => {
280
+ jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
281
+
282
+ // Create state with new format: internal.user
283
+ const internalState = btoa(JSON.stringify({ returnPathname: '/dashboard' }))
284
+ .replace(/\+/g, '-')
285
+ .replace(/\//g, '_');
286
+ const userState = 'custom-user-state-string';
287
+ const state = `${internalState}.${userState}`;
288
+
289
+ request.nextUrl.searchParams.set('code', 'test-code');
290
+ request.nextUrl.searchParams.set('state', state);
291
+
292
+ const onSuccess = jest.fn();
293
+ const handler = handleAuth({ onSuccess });
294
+ await handler(request);
295
+
296
+ // Verify onSuccess was called with the custom state string
297
+ expect(onSuccess).toHaveBeenCalledWith(
298
+ expect.objectContaining({
299
+ ...mockAuthResponse,
300
+ state: 'custom-user-state-string',
301
+ }),
302
+ );
303
+
304
+ // Verify the redirect went to the correct path
305
+ const response = await handler(request);
306
+ expect(response.headers.get('Location')).toContain('/dashboard');
307
+ });
308
+
309
+ it('should handle state without custom data', async () => {
310
+ jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
311
+
312
+ // State with only returnPathname
313
+ const state = btoa(JSON.stringify({ returnPathname: '/profile' }));
314
+
315
+ request.nextUrl.searchParams.set('code', 'test-code');
316
+ request.nextUrl.searchParams.set('state', state);
317
+
318
+ const onSuccess = jest.fn();
319
+ const handler = handleAuth({ onSuccess });
320
+ await handler(request);
321
+
322
+ // Verify onSuccess was called without state property when no custom data exists
323
+ expect(onSuccess).toHaveBeenCalledWith(
324
+ expect.objectContaining({
325
+ ...mockAuthResponse,
326
+ state: undefined,
327
+ }),
328
+ );
329
+ });
330
+
331
+ it('should handle backward compatibility with old state format', async () => {
332
+ jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
333
+
334
+ // Old format: just returnPathname
335
+ const state = btoa(JSON.stringify({ returnPathname: '/old-path' }));
336
+
337
+ request.nextUrl.searchParams.set('code', 'test-code');
338
+ request.nextUrl.searchParams.set('state', state);
339
+
340
+ const handler = handleAuth();
341
+ const response = await handler(request);
342
+
343
+ // Should still redirect correctly
344
+ expect(response.headers.get('Location')).toContain('/old-path');
345
+ });
278
346
  });
279
347
  });
@@ -5,6 +5,37 @@ import { saveSession } from './session.js';
5
5
  import { errorResponseWithFallback, redirectWithFallback } from './utils.js';
6
6
  import { getWorkOS } from './workos.js';
7
7
 
8
+ function handleState(state: string | null) {
9
+ let returnPathname: string | undefined = undefined;
10
+ let userState: string | undefined;
11
+ if (state?.includes('.')) {
12
+ const [internal, ...rest] = state.split('.');
13
+ userState = rest.join('.');
14
+ try {
15
+ // Reverse URL-safe base64 encoding
16
+ const decoded = internal.replace(/-/g, '+').replace(/_/g, '/');
17
+ returnPathname = JSON.parse(atob(decoded)).returnPathname;
18
+ } catch {
19
+ // Malformed internal part, ignore it
20
+ }
21
+ } else if (state) {
22
+ try {
23
+ const decoded = JSON.parse(atob(state));
24
+ if (decoded.returnPathname) {
25
+ returnPathname = decoded.returnPathname;
26
+ } else {
27
+ userState = state;
28
+ }
29
+ } catch {
30
+ userState = state;
31
+ }
32
+ }
33
+ return {
34
+ returnPathname,
35
+ state: userState,
36
+ };
37
+ }
38
+
8
39
  export function handleAuth(options: HandleAuthOptions = {}) {
9
40
  const { returnPathname: returnPathnameOption = '/', baseURL, onSuccess, onError } = options;
10
41
 
@@ -20,7 +51,8 @@ export function handleAuth(options: HandleAuthOptions = {}) {
20
51
  return async function GET(request: NextRequest) {
21
52
  const code = request.nextUrl.searchParams.get('code');
22
53
  const state = request.nextUrl.searchParams.get('state');
23
- let returnPathname = state && state !== 'null' ? JSON.parse(atob(state)).returnPathname : null;
54
+
55
+ const { state: customState, returnPathname: returnPathnameState } = handleState(state);
24
56
 
25
57
  if (code) {
26
58
  try {
@@ -41,7 +73,7 @@ export function handleAuth(options: HandleAuthOptions = {}) {
41
73
  url.searchParams.delete('state');
42
74
 
43
75
  // Redirect to the requested path and store the session
44
- returnPathname = returnPathname ?? returnPathnameOption;
76
+ const returnPathname = returnPathnameState ?? returnPathnameOption;
45
77
 
46
78
  // Extract the search params if they are present
47
79
  if (returnPathname.includes('?')) {
@@ -72,6 +104,7 @@ export function handleAuth(options: HandleAuthOptions = {}) {
72
104
  oauthTokens,
73
105
  authenticationMethod,
74
106
  organizationId,
107
+ state: customState,
75
108
  });
76
109
  }
77
110
 
@@ -12,13 +12,21 @@ async function getAuthorizationUrl(options: GetAuthURLOptions = {}) {
12
12
  redirectUri = headersList.get('x-redirect-uri'),
13
13
  loginHint,
14
14
  prompt,
15
+ state: customState,
15
16
  } = options;
16
17
 
18
+ const internalState = returnPathname
19
+ ? btoa(JSON.stringify({ returnPathname })).replace(/\+/g, '-').replace(/\//g, '_')
20
+ : null;
21
+
22
+ const finalState =
23
+ internalState && customState ? `${internalState}.${customState}` : internalState || customState || undefined;
24
+
17
25
  return getWorkOS().userManagement.getAuthorizationUrl({
18
26
  provider: 'authkit',
19
27
  clientId: WORKOS_CLIENT_ID,
20
28
  redirectUri: redirectUri ?? WORKOS_REDIRECT_URI,
21
- state: returnPathname ? btoa(JSON.stringify({ returnPathname })) : undefined,
29
+ state: finalState,
22
30
  screenHint,
23
31
  organizationId,
24
32
  loginHint,
package/src/interfaces.ts CHANGED
@@ -12,6 +12,7 @@ export interface HandleAuthSuccessData extends Session {
12
12
  oauthTokens?: OauthTokens;
13
13
  organizationId?: string;
14
14
  authenticationMethod?: AuthenticationResponse['authenticationMethod'];
15
+ state?: string | undefined;
15
16
  }
16
17
 
17
18
  export interface Impersonator {
@@ -67,6 +68,7 @@ export interface GetAuthURLOptions {
67
68
  redirectUri?: string;
68
69
  loginHint?: string;
69
70
  prompt?: 'consent';
71
+ state?: string;
70
72
  }
71
73
 
72
74
  export interface AuthkitMiddlewareAuth {
@@ -146,7 +146,12 @@ describe('session.ts', () => {
146
146
 
147
147
  await withAuth({ ensureSignedIn: true });
148
148
 
149
- const pathname = encodeURIComponent(btoa(JSON.stringify({ returnPathname: '/protected?test=123' })));
149
+ // URL-safe base64 encoding
150
+ const pathname = encodeURIComponent(
151
+ btoa(JSON.stringify({ returnPathname: '/protected?test=123' }))
152
+ .replace(/\+/g, '-')
153
+ .replace(/\//g, '_'),
154
+ );
150
155
 
151
156
  expect(redirect).toHaveBeenCalledWith(expect.stringContaining(pathname));
152
157
  });
package/src/workos.ts CHANGED
@@ -2,7 +2,7 @@ import { WorkOS } from '@workos-inc/node';
2
2
  import { WORKOS_API_HOSTNAME, WORKOS_API_KEY, WORKOS_API_HTTPS, WORKOS_API_PORT } from './env-variables.js';
3
3
  import { lazy } from './utils.js';
4
4
 
5
- export const VERSION = '2.9.0';
5
+ export const VERSION = '2.10.0';
6
6
 
7
7
  const options = {
8
8
  apiHostname: WORKOS_API_HOSTNAME,