@workos-inc/authkit-nextjs 2.16.0 → 2.17.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.
@@ -11,11 +11,12 @@ const WORKOS_COOKIE_DOMAIN = getEnvVariable('WORKOS_COOKIE_DOMAIN');
11
11
  const WORKOS_COOKIE_MAX_AGE = getEnvVariable('WORKOS_COOKIE_MAX_AGE');
12
12
  const WORKOS_COOKIE_NAME = getEnvVariable('WORKOS_COOKIE_NAME');
13
13
  const WORKOS_COOKIE_SAMESITE = getEnvVariable('WORKOS_COOKIE_SAMESITE');
14
- const WORKOS_DISABLE_PKCE = getEnvVariable('WORKOS_DISABLE_PKCE');
14
+ const WORKOS_CLAIM_TOKEN = getEnvVariable('WORKOS_CLAIM_TOKEN');
15
+ const WORKOS_ENABLE_PKCE = getEnvVariable('WORKOS_ENABLE_PKCE');
15
16
  // Required env variables
16
17
  const WORKOS_API_KEY = (_a = getEnvVariable('WORKOS_API_KEY')) !== null && _a !== void 0 ? _a : '';
17
18
  const WORKOS_CLIENT_ID = (_b = getEnvVariable('WORKOS_CLIENT_ID')) !== null && _b !== void 0 ? _b : '';
18
19
  const WORKOS_COOKIE_PASSWORD = (_c = getEnvVariable('WORKOS_COOKIE_PASSWORD')) !== null && _c !== void 0 ? _c : '';
19
20
  const WORKOS_REDIRECT_URI = (_d = process.env.NEXT_PUBLIC_WORKOS_REDIRECT_URI) !== null && _d !== void 0 ? _d : '';
20
- export { WORKOS_API_HOSTNAME, WORKOS_API_HTTPS, WORKOS_API_KEY, WORKOS_API_PORT, WORKOS_CLIENT_ID, WORKOS_COOKIE_DOMAIN, WORKOS_COOKIE_MAX_AGE, WORKOS_COOKIE_NAME, WORKOS_COOKIE_PASSWORD, WORKOS_REDIRECT_URI, WORKOS_COOKIE_SAMESITE, WORKOS_DISABLE_PKCE, };
21
+ export { WORKOS_API_HOSTNAME, WORKOS_API_HTTPS, WORKOS_API_KEY, WORKOS_API_PORT, WORKOS_CLAIM_TOKEN, WORKOS_CLIENT_ID, WORKOS_COOKIE_DOMAIN, WORKOS_COOKIE_MAX_AGE, WORKOS_COOKIE_NAME, WORKOS_COOKIE_PASSWORD, WORKOS_REDIRECT_URI, WORKOS_COOKIE_SAMESITE, WORKOS_ENABLE_PKCE, };
21
22
  //# sourceMappingURL=env-variables.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"env-variables.js","sourceRoot":"","sources":["../../src/env-variables.ts"],"names":[],"mappings":"AAAA,0BAA0B;;AAE1B,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,yBAAyB;AACzB,MAAM,mBAAmB,GAAG,cAAc,CAAC,qBAAqB,CAAC,CAAC;AAClE,MAAM,gBAAgB,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAC;AAC5D,MAAM,eAAe,GAAG,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAC1D,MAAM,oBAAoB,GAAG,cAAc,CAAC,sBAAsB,CAAC,CAAC;AACpE,MAAM,qBAAqB,GAAG,cAAc,CAAC,uBAAuB,CAAC,CAAC;AACtE,MAAM,kBAAkB,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;AAChE,MAAM,sBAAsB,GAAG,cAAc,CAAC,wBAAwB,CAA0C,CAAC;AACjH,MAAM,mBAAmB,GAAG,cAAc,CAAC,qBAAqB,CAAC,CAAC;AAElE,yBAAyB;AACzB,MAAM,cAAc,GAAG,MAAA,cAAc,CAAC,gBAAgB,CAAC,mCAAI,EAAE,CAAC;AAC9D,MAAM,gBAAgB,GAAG,MAAA,cAAc,CAAC,kBAAkB,CAAC,mCAAI,EAAE,CAAC;AAClE,MAAM,sBAAsB,GAAG,MAAA,cAAc,CAAC,wBAAwB,CAAC,mCAAI,EAAE,CAAC;AAC9E,MAAM,mBAAmB,GAAG,MAAA,OAAO,CAAC,GAAG,CAAC,+BAA+B,mCAAI,EAAE,CAAC;AAE9E,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,GACpB,CAAC"}
1
+ {"version":3,"file":"env-variables.js","sourceRoot":"","sources":["../../src/env-variables.ts"],"names":[],"mappings":"AAAA,0BAA0B;;AAE1B,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,yBAAyB;AACzB,MAAM,mBAAmB,GAAG,cAAc,CAAC,qBAAqB,CAAC,CAAC;AAClE,MAAM,gBAAgB,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAC;AAC5D,MAAM,eAAe,GAAG,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAC1D,MAAM,oBAAoB,GAAG,cAAc,CAAC,sBAAsB,CAAC,CAAC;AACpE,MAAM,qBAAqB,GAAG,cAAc,CAAC,uBAAuB,CAAC,CAAC;AACtE,MAAM,kBAAkB,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;AAChE,MAAM,sBAAsB,GAAG,cAAc,CAAC,wBAAwB,CAA0C,CAAC;AACjH,MAAM,kBAAkB,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;AAChE,MAAM,kBAAkB,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;AAEhE,yBAAyB;AACzB,MAAM,cAAc,GAAG,MAAA,cAAc,CAAC,gBAAgB,CAAC,mCAAI,EAAE,CAAC;AAC9D,MAAM,gBAAgB,GAAG,MAAA,cAAc,CAAC,kBAAkB,CAAC,mCAAI,EAAE,CAAC;AAClE,MAAM,sBAAsB,GAAG,MAAA,cAAc,CAAC,wBAAwB,CAAC,mCAAI,EAAE,CAAC;AAC9E,MAAM,mBAAmB,GAAG,MAAA,OAAO,CAAC,GAAG,CAAC,+BAA+B,mCAAI,EAAE,CAAC;AAE9E,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,GACnB,CAAC"}
@@ -1,7 +1,31 @@
1
1
  import { sealData } from 'iron-session';
2
2
  import { headers } from 'next/headers';
3
- import { WORKOS_CLIENT_ID, WORKOS_COOKIE_PASSWORD, WORKOS_DISABLE_PKCE, WORKOS_REDIRECT_URI } from './env-variables.js';
3
+ import { WORKOS_CLAIM_TOKEN, WORKOS_CLIENT_ID, WORKOS_COOKIE_PASSWORD, WORKOS_ENABLE_PKCE, WORKOS_REDIRECT_URI, } from './env-variables.js';
4
4
  import { getWorkOS } from './workos.js';
5
+ async function fetchClaimNonce(baseURL) {
6
+ try {
7
+ const response = await fetch(`${baseURL}/x/one-shot-environments/claim-nonces`, {
8
+ method: 'POST',
9
+ headers: { 'Content-Type': 'application/json' },
10
+ body: JSON.stringify({
11
+ client_id: WORKOS_CLIENT_ID,
12
+ claim_token: WORKOS_CLAIM_TOKEN,
13
+ }),
14
+ });
15
+ if (!response.ok) {
16
+ if (response.status !== 409) {
17
+ console.warn(`[authkit-nextjs]: Failed to exchange WORKOS_CLAIM_TOKEN (${response.status}). Try removing WORKOS_CLAIM_TOKEN from your environment variables.`);
18
+ }
19
+ return null;
20
+ }
21
+ const data = await response.json();
22
+ return data.nonce;
23
+ }
24
+ catch (error) {
25
+ console.warn('[authkit-nextjs]: Failed to exchange WORKOS_CLAIM_TOKEN. Try removing WORKOS_CLAIM_TOKEN from your environment variables.', error);
26
+ return null;
27
+ }
28
+ }
5
29
  async function getAuthorizationUrl(options = {}) {
6
30
  var _a;
7
31
  const { returnPathname, screenHint, organizationId, loginHint, prompt, state: customState } = options;
@@ -13,6 +37,7 @@ async function getAuthorizationUrl(options = {}) {
13
37
  const internalState = returnPathname
14
38
  ? btoa(JSON.stringify({ returnPathname })).replace(/\+/g, '-').replace(/\//g, '_')
15
39
  : null;
40
+ const claimNonce = WORKOS_CLAIM_TOKEN ? await fetchClaimNonce(getWorkOS().baseURL) : null;
16
41
  const finalState = internalState && customState ? `${internalState}.${customState}` : internalState || customState || undefined;
17
42
  const baseOptions = {
18
43
  provider: 'authkit',
@@ -23,18 +48,19 @@ async function getAuthorizationUrl(options = {}) {
23
48
  organizationId,
24
49
  loginHint,
25
50
  prompt,
51
+ ...(claimNonce && { claimNonce }),
26
52
  };
27
- if (WORKOS_DISABLE_PKCE === 'true') {
28
- return { url: getWorkOS().userManagement.getAuthorizationUrl(baseOptions), pkceCookieValue: undefined };
53
+ if (WORKOS_ENABLE_PKCE === 'true') {
54
+ const pkce = await getWorkOS().pkce.generate();
55
+ const pkceCookieValue = await sealData({ codeVerifier: pkce.codeVerifier }, { password: WORKOS_COOKIE_PASSWORD, ttl: 600 });
56
+ const url = getWorkOS().userManagement.getAuthorizationUrl({
57
+ ...baseOptions,
58
+ codeChallenge: pkce.codeChallenge,
59
+ codeChallengeMethod: pkce.codeChallengeMethod,
60
+ });
61
+ return { url, pkceCookieValue };
29
62
  }
30
- const pkce = await getWorkOS().pkce.generate();
31
- const pkceCookieValue = await sealData({ codeVerifier: pkce.codeVerifier }, { password: WORKOS_COOKIE_PASSWORD, ttl: 600 });
32
- const url = getWorkOS().userManagement.getAuthorizationUrl({
33
- ...baseOptions,
34
- codeChallenge: pkce.codeChallenge,
35
- codeChallengeMethod: pkce.codeChallengeMethod,
36
- });
37
- return { url, pkceCookieValue };
63
+ return { url: getWorkOS().userManagement.getAuthorizationUrl(baseOptions), pkceCookieValue: undefined };
38
64
  }
39
65
  export { getAuthorizationUrl };
40
66
  //# sourceMappingURL=get-authorization-url.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-authorization-url.js","sourceRoot":"","sources":["../../src/get-authorization-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAExH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,KAAK,UAAU,mBAAmB,CAAC,UAA6B,EAAE;;IAChE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACtG,IAAI,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,WAAW,GAAG,MAAA,WAAW,CAAC,GAAG,CAAC,gBAAgB,CAAC,mCAAI,SAAS,CAAC;IAC/D,CAAC;IAED,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,MAAM,WAAW,GAAG;QAClB,QAAQ,EAAE,SAAkB;QAC5B,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;IAEF,IAAI,mBAAmB,KAAK,MAAM,EAAE,CAAC;QACnC,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,cAAc,CAAC,mBAAmB,CAAC,WAAW,CAAC,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;IAC1G,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC/C,MAAM,eAAe,GAAG,MAAM,QAAQ,CACpC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,EACnC,EAAE,QAAQ,EAAE,sBAAsB,EAAE,GAAG,EAAE,GAAG,EAAE,CAC/C,CAAC;IACF,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC,cAAc,CAAC,mBAAmB,CAAC;QACzD,GAAG,WAAW;QACd,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;KAC9C,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC;AAClC,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
1
+ {"version":3,"file":"get-authorization-url.js","sourceRoot":"","sources":["../../src/get-authorization-url.ts"],"names":[],"mappings":"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"}
@@ -5,9 +5,10 @@ declare const WORKOS_COOKIE_DOMAIN: string | undefined;
5
5
  declare const WORKOS_COOKIE_MAX_AGE: string | undefined;
6
6
  declare const WORKOS_COOKIE_NAME: string | undefined;
7
7
  declare const WORKOS_COOKIE_SAMESITE: "lax" | "strict" | "none" | undefined;
8
- declare const WORKOS_DISABLE_PKCE: string | undefined;
8
+ declare const WORKOS_CLAIM_TOKEN: string | undefined;
9
+ declare const WORKOS_ENABLE_PKCE: string | undefined;
9
10
  declare const WORKOS_API_KEY: string;
10
11
  declare const WORKOS_CLIENT_ID: string;
11
12
  declare const WORKOS_COOKIE_PASSWORD: string;
12
13
  declare const WORKOS_REDIRECT_URI: string;
13
- export { WORKOS_API_HOSTNAME, WORKOS_API_HTTPS, WORKOS_API_KEY, WORKOS_API_PORT, WORKOS_CLIENT_ID, WORKOS_COOKIE_DOMAIN, WORKOS_COOKIE_MAX_AGE, WORKOS_COOKIE_NAME, WORKOS_COOKIE_PASSWORD, WORKOS_REDIRECT_URI, WORKOS_COOKIE_SAMESITE, WORKOS_DISABLE_PKCE, };
14
+ export { WORKOS_API_HOSTNAME, WORKOS_API_HTTPS, WORKOS_API_KEY, WORKOS_API_PORT, WORKOS_CLAIM_TOKEN, WORKOS_CLIENT_ID, WORKOS_COOKIE_DOMAIN, WORKOS_COOKIE_MAX_AGE, WORKOS_COOKIE_NAME, WORKOS_COOKIE_PASSWORD, WORKOS_REDIRECT_URI, WORKOS_COOKIE_SAMESITE, WORKOS_ENABLE_PKCE, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos-inc/authkit-nextjs",
3
- "version": "2.16.0",
3
+ "version": "2.17.0",
4
4
  "description": "Authentication and session helpers for using WorkOS & AuthKit with Next.js",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -23,7 +23,7 @@
23
23
  }
24
24
  },
25
25
  "dependencies": {
26
- "@workos-inc/node": "^8.7.0",
26
+ "@workos-inc/node": "^8.9.0",
27
27
  "iron-session": "^8.0.4",
28
28
  "jose": "^5.10.0",
29
29
  "path-to-regexp": "^6.3.0"
@@ -12,7 +12,8 @@ const WORKOS_COOKIE_DOMAIN = getEnvVariable('WORKOS_COOKIE_DOMAIN');
12
12
  const WORKOS_COOKIE_MAX_AGE = getEnvVariable('WORKOS_COOKIE_MAX_AGE');
13
13
  const WORKOS_COOKIE_NAME = getEnvVariable('WORKOS_COOKIE_NAME');
14
14
  const WORKOS_COOKIE_SAMESITE = getEnvVariable('WORKOS_COOKIE_SAMESITE') as 'lax' | 'strict' | 'none' | undefined;
15
- const WORKOS_DISABLE_PKCE = getEnvVariable('WORKOS_DISABLE_PKCE');
15
+ const WORKOS_CLAIM_TOKEN = getEnvVariable('WORKOS_CLAIM_TOKEN');
16
+ const WORKOS_ENABLE_PKCE = getEnvVariable('WORKOS_ENABLE_PKCE');
16
17
 
17
18
  // Required env variables
18
19
  const WORKOS_API_KEY = getEnvVariable('WORKOS_API_KEY') ?? '';
@@ -25,6 +26,7 @@ export {
25
26
  WORKOS_API_HTTPS,
26
27
  WORKOS_API_KEY,
27
28
  WORKOS_API_PORT,
29
+ WORKOS_CLAIM_TOKEN,
28
30
  WORKOS_CLIENT_ID,
29
31
  WORKOS_COOKIE_DOMAIN,
30
32
  WORKOS_COOKIE_MAX_AGE,
@@ -32,5 +34,5 @@ export {
32
34
  WORKOS_COOKIE_PASSWORD,
33
35
  WORKOS_REDIRECT_URI,
34
36
  WORKOS_COOKIE_SAMESITE,
35
- WORKOS_DISABLE_PKCE,
37
+ WORKOS_ENABLE_PKCE,
36
38
  };
@@ -5,6 +5,7 @@ import { getWorkOS } from './workos.js';
5
5
  // Mock dependencies
6
6
  const { fakeWorkosInstance } = vi.hoisted(() => ({
7
7
  fakeWorkosInstance: {
8
+ baseURL: 'https://api.workos.com',
8
9
  userManagement: {
9
10
  getAuthorizationUrl: vi.fn(),
10
11
  },
@@ -26,7 +27,7 @@ describe('getAuthorizationUrl', () => {
26
27
  const workos = getWorkOS();
27
28
  beforeEach(() => {
28
29
  vi.clearAllMocks();
29
- delete process.env.WORKOS_DISABLE_PKCE;
30
+ delete process.env.WORKOS_ENABLE_PKCE;
30
31
  fakeWorkosInstance.pkce.generate.mockResolvedValue({
31
32
  codeVerifier: 'test-code-verifier',
32
33
  codeChallenge: 'test-code-challenge',
@@ -70,45 +71,122 @@ describe('getAuthorizationUrl', () => {
70
71
  );
71
72
  });
72
73
 
73
- describe('PKCE', () => {
74
- it('generates PKCE pair and includes codeChallenge in authorization URL', async () => {
74
+ describe('claim nonce', () => {
75
+ afterEach(() => {
76
+ delete process.env.WORKOS_CLAIM_TOKEN;
77
+ });
78
+
79
+ it('does not fetch nonce when WORKOS_CLAIM_TOKEN is not set', async () => {
80
+ const fetchSpy = vi.spyOn(globalThis, 'fetch');
75
81
  vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
76
82
 
77
- const result = await getAuthorizationUrl({});
83
+ await getAuthorizationUrl({});
78
84
 
79
- expect(fakeWorkosInstance.pkce.generate).toHaveBeenCalled();
85
+ expect(fetchSpy).not.toHaveBeenCalledWith(expect.stringContaining('claim-nonces'), expect.anything());
80
86
  expect(workos.userManagement.getAuthorizationUrl).toHaveBeenCalledWith(
87
+ expect.not.objectContaining({ claimNonce: expect.any(String) }),
88
+ );
89
+ fetchSpy.mockRestore();
90
+ });
91
+
92
+ it('fetches nonce and passes claimNonce when WORKOS_CLAIM_TOKEN is set', async () => {
93
+ process.env.WORKOS_CLAIM_TOKEN = 'test-claim-token';
94
+ const fetchSpy = vi
95
+ .spyOn(globalThis, 'fetch')
96
+ .mockResolvedValueOnce(new Response(JSON.stringify({ nonce: 'test-nonce' }), { status: 201 }));
97
+
98
+ vi.resetModules();
99
+ const { getAuthorizationUrl: freshGetAuthorizationUrl } = await import('./get-authorization-url.js');
100
+ vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
101
+
102
+ await freshGetAuthorizationUrl({});
103
+
104
+ expect(fetchSpy).toHaveBeenCalledWith(
105
+ 'https://api.workos.com/x/one-shot-environments/claim-nonces',
81
106
  expect.objectContaining({
82
- codeChallenge: 'test-code-challenge',
83
- codeChallengeMethod: 'S256',
107
+ method: 'POST',
108
+ headers: { 'Content-Type': 'application/json' },
109
+ body: JSON.stringify({ client_id: 'client_1234567890', claim_token: 'test-claim-token' }),
84
110
  }),
85
111
  );
86
- expect(result.url).toBe('mock-url');
87
- expect(result.pkceCookieValue).toBeDefined();
88
- expect(result.pkceCookieValue).not.toBe('');
112
+ expect(workos.userManagement.getAuthorizationUrl).toHaveBeenCalledWith(
113
+ expect.objectContaining({ claimNonce: 'test-nonce' }),
114
+ );
115
+ fetchSpy.mockRestore();
89
116
  });
90
117
 
91
- it('returns sealed cookie value for the verifier', async () => {
118
+ it('proceeds without nonce on network error', async () => {
119
+ process.env.WORKOS_CLAIM_TOKEN = 'test-claim-token';
120
+ const fetchSpy = vi.spyOn(globalThis, 'fetch').mockRejectedValueOnce(new Error('Network error'));
121
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
122
+
123
+ vi.resetModules();
124
+ const { getAuthorizationUrl: freshGetAuthorizationUrl } = await import('./get-authorization-url.js');
92
125
  vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
93
126
 
94
- const result = await getAuthorizationUrl({});
127
+ await freshGetAuthorizationUrl({});
95
128
 
96
- // pkceCookieValue should be a sealed (encrypted) string
97
- expect(typeof result.pkceCookieValue).toBe('string');
98
- expect(result.pkceCookieValue!.length).toBeGreaterThan(0);
129
+ expect(workos.userManagement.getAuthorizationUrl).toHaveBeenCalledWith(
130
+ expect.not.objectContaining({ claimNonce: expect.any(String) }),
131
+ );
132
+ expect(warnSpy).toHaveBeenCalledWith(
133
+ '[authkit-nextjs]: Failed to exchange WORKOS_CLAIM_TOKEN. Try removing WORKOS_CLAIM_TOKEN from your environment variables.',
134
+ expect.any(Error),
135
+ );
136
+ fetchSpy.mockRestore();
137
+ warnSpy.mockRestore();
99
138
  });
100
139
 
101
- it('skips PKCE when WORKOS_DISABLE_PKCE is set to true', async () => {
102
- process.env.WORKOS_DISABLE_PKCE = 'true';
140
+ it('proceeds without nonce on non-OK response', async () => {
141
+ process.env.WORKOS_CLAIM_TOKEN = 'test-claim-token';
142
+ const fetchSpy = vi
143
+ .spyOn(globalThis, 'fetch')
144
+ .mockResolvedValueOnce(new Response('Unauthorized', { status: 401 }));
145
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
103
146
 
104
- // Re-import to pick up the new env var
105
147
  vi.resetModules();
106
148
  const { getAuthorizationUrl: freshGetAuthorizationUrl } = await import('./get-authorization-url.js');
149
+ vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
107
150
 
151
+ await freshGetAuthorizationUrl({});
152
+
153
+ expect(workos.userManagement.getAuthorizationUrl).toHaveBeenCalledWith(
154
+ expect.not.objectContaining({ claimNonce: expect.any(String) }),
155
+ );
156
+ expect(warnSpy).toHaveBeenCalledWith(
157
+ '[authkit-nextjs]: Failed to exchange WORKOS_CLAIM_TOKEN (401). Try removing WORKOS_CLAIM_TOKEN from your environment variables.',
158
+ );
159
+ fetchSpy.mockRestore();
160
+ warnSpy.mockRestore();
161
+ });
162
+
163
+ it('works with PKCE disabled', async () => {
164
+ process.env.WORKOS_CLAIM_TOKEN = 'test-claim-token';
165
+ process.env.WORKOS_DISABLE_PKCE = 'true';
166
+ const fetchSpy = vi
167
+ .spyOn(globalThis, 'fetch')
168
+ .mockResolvedValueOnce(new Response(JSON.stringify({ nonce: 'test-nonce' }), { status: 201 }));
169
+
170
+ vi.resetModules();
171
+ const { getAuthorizationUrl: freshGetAuthorizationUrl } = await import('./get-authorization-url.js');
108
172
  vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
109
173
 
110
174
  const result = await freshGetAuthorizationUrl({});
111
175
 
176
+ expect(workos.userManagement.getAuthorizationUrl).toHaveBeenCalledWith(
177
+ expect.objectContaining({ claimNonce: 'test-nonce' }),
178
+ );
179
+ expect(result.pkceCookieValue).toBeUndefined();
180
+ fetchSpy.mockRestore();
181
+ });
182
+ });
183
+
184
+ describe('PKCE', () => {
185
+ it('skips PKCE by default', async () => {
186
+ vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
187
+
188
+ const result = await getAuthorizationUrl({});
189
+
112
190
  expect(fakeWorkosInstance.pkce.generate).not.toHaveBeenCalled();
113
191
  expect(workos.userManagement.getAuthorizationUrl).toHaveBeenCalledWith(
114
192
  expect.not.objectContaining({
@@ -117,5 +195,43 @@ describe('getAuthorizationUrl', () => {
117
195
  );
118
196
  expect(result.pkceCookieValue).toBeUndefined();
119
197
  });
198
+
199
+ it('generates PKCE pair when WORKOS_ENABLE_PKCE is set to true', async () => {
200
+ process.env.WORKOS_ENABLE_PKCE = 'true';
201
+
202
+ // Re-import to pick up the new env var
203
+ vi.resetModules();
204
+ const { getAuthorizationUrl: freshGetAuthorizationUrl } = await import('./get-authorization-url.js');
205
+
206
+ vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
207
+
208
+ const result = await freshGetAuthorizationUrl({});
209
+
210
+ expect(fakeWorkosInstance.pkce.generate).toHaveBeenCalled();
211
+ expect(workos.userManagement.getAuthorizationUrl).toHaveBeenCalledWith(
212
+ expect.objectContaining({
213
+ codeChallenge: 'test-code-challenge',
214
+ codeChallengeMethod: 'S256',
215
+ }),
216
+ );
217
+ expect(result.url).toBe('mock-url');
218
+ expect(result.pkceCookieValue).toBeDefined();
219
+ expect(result.pkceCookieValue).not.toBe('');
220
+ });
221
+
222
+ it('returns sealed cookie value for the verifier when PKCE is enabled', async () => {
223
+ process.env.WORKOS_ENABLE_PKCE = 'true';
224
+
225
+ vi.resetModules();
226
+ const { getAuthorizationUrl: freshGetAuthorizationUrl } = await import('./get-authorization-url.js');
227
+
228
+ vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
229
+
230
+ const result = await freshGetAuthorizationUrl({});
231
+
232
+ // pkceCookieValue should be a sealed (encrypted) string
233
+ expect(typeof result.pkceCookieValue).toBe('string');
234
+ expect(result.pkceCookieValue!.length).toBeGreaterThan(0);
235
+ });
120
236
  });
121
237
  });
@@ -1,9 +1,44 @@
1
1
  import { sealData } from 'iron-session';
2
2
  import { headers } from 'next/headers';
3
- import { WORKOS_CLIENT_ID, WORKOS_COOKIE_PASSWORD, WORKOS_DISABLE_PKCE, WORKOS_REDIRECT_URI } from './env-variables.js';
3
+ import {
4
+ WORKOS_CLAIM_TOKEN,
5
+ WORKOS_CLIENT_ID,
6
+ WORKOS_COOKIE_PASSWORD,
7
+ WORKOS_ENABLE_PKCE,
8
+ WORKOS_REDIRECT_URI,
9
+ } from './env-variables.js';
4
10
  import { GetAuthURLOptions, GetAuthURLResult } from './interfaces.js';
5
11
  import { getWorkOS } from './workos.js';
6
12
 
13
+ async function fetchClaimNonce(baseURL: string): Promise<string | null> {
14
+ try {
15
+ const response = await fetch(`${baseURL}/x/one-shot-environments/claim-nonces`, {
16
+ method: 'POST',
17
+ headers: { 'Content-Type': 'application/json' },
18
+ body: JSON.stringify({
19
+ client_id: WORKOS_CLIENT_ID,
20
+ claim_token: WORKOS_CLAIM_TOKEN,
21
+ }),
22
+ });
23
+ if (!response.ok) {
24
+ if (response.status !== 409) {
25
+ console.warn(
26
+ `[authkit-nextjs]: Failed to exchange WORKOS_CLAIM_TOKEN (${response.status}). Try removing WORKOS_CLAIM_TOKEN from your environment variables.`,
27
+ );
28
+ }
29
+ return null;
30
+ }
31
+ const data = await response.json();
32
+ return data.nonce;
33
+ } catch (error) {
34
+ console.warn(
35
+ '[authkit-nextjs]: Failed to exchange WORKOS_CLAIM_TOKEN. Try removing WORKOS_CLAIM_TOKEN from your environment variables.',
36
+ error,
37
+ );
38
+ return null;
39
+ }
40
+ }
41
+
7
42
  async function getAuthorizationUrl(options: GetAuthURLOptions = {}): Promise<GetAuthURLResult> {
8
43
  const { returnPathname, screenHint, organizationId, loginHint, prompt, state: customState } = options;
9
44
  let redirectUri = options.redirectUri;
@@ -16,6 +51,8 @@ async function getAuthorizationUrl(options: GetAuthURLOptions = {}): Promise<Get
16
51
  ? btoa(JSON.stringify({ returnPathname })).replace(/\+/g, '-').replace(/\//g, '_')
17
52
  : null;
18
53
 
54
+ const claimNonce = WORKOS_CLAIM_TOKEN ? await fetchClaimNonce(getWorkOS().baseURL) : null;
55
+
19
56
  const finalState =
20
57
  internalState && customState ? `${internalState}.${customState}` : internalState || customState || undefined;
21
58
 
@@ -28,24 +65,25 @@ async function getAuthorizationUrl(options: GetAuthURLOptions = {}): Promise<Get
28
65
  organizationId,
29
66
  loginHint,
30
67
  prompt,
68
+ ...(claimNonce && { claimNonce }),
31
69
  };
32
70
 
33
- if (WORKOS_DISABLE_PKCE === 'true') {
34
- return { url: getWorkOS().userManagement.getAuthorizationUrl(baseOptions), pkceCookieValue: undefined };
71
+ if (WORKOS_ENABLE_PKCE === 'true') {
72
+ const pkce = await getWorkOS().pkce.generate();
73
+ const pkceCookieValue = await sealData(
74
+ { codeVerifier: pkce.codeVerifier },
75
+ { password: WORKOS_COOKIE_PASSWORD, ttl: 600 },
76
+ );
77
+ const url = getWorkOS().userManagement.getAuthorizationUrl({
78
+ ...baseOptions,
79
+ codeChallenge: pkce.codeChallenge,
80
+ codeChallengeMethod: pkce.codeChallengeMethod,
81
+ });
82
+
83
+ return { url, pkceCookieValue };
35
84
  }
36
85
 
37
- const pkce = await getWorkOS().pkce.generate();
38
- const pkceCookieValue = await sealData(
39
- { codeVerifier: pkce.codeVerifier },
40
- { password: WORKOS_COOKIE_PASSWORD, ttl: 600 },
41
- );
42
- const url = getWorkOS().userManagement.getAuthorizationUrl({
43
- ...baseOptions,
44
- codeChallenge: pkce.codeChallenge,
45
- codeChallengeMethod: pkce.codeChallengeMethod,
46
- });
47
-
48
- return { url, pkceCookieValue };
86
+ return { url: getWorkOS().userManagement.getAuthorizationUrl(baseOptions), pkceCookieValue: undefined };
49
87
  }
50
88
 
51
89
  export { getAuthorizationUrl };