@workos-inc/authkit-nextjs 2.13.0 → 2.14.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
@@ -9,7 +9,7 @@ The AuthKit library for Next.js provides convenient helpers for authentication a
9
9
  Install the package with:
10
10
 
11
11
  ```
12
- npm i @workos-inc/authkit-nextjs
12
+ pnpm i @workos-inc/authkit-nextjs
13
13
  ```
14
14
 
15
15
  or
@@ -159,10 +159,18 @@ export default authkitMiddleware();
159
159
  // For Next.js 16+, you can also use: export { default as proxy } from './proxy';
160
160
 
161
161
  // Match against pages that require auth
162
- // Leave this out if you want auth on every resource (including images, css etc.)
163
162
  export const config = { matcher: ['/', '/admin'] };
164
163
  ```
165
164
 
165
+ > [!WARNING]
166
+ > Using a catch-all matcher pattern can intercept static assets (CSS, images, fonts), causing styles to break—particularly with Tailwind CSS v4. If you need a broad matcher, exclude Next.js static paths:
167
+ >
168
+ > ```ts
169
+ > export const config = {
170
+ > matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
171
+ > };
172
+ > ```
173
+
166
174
  The proxy/middleware can be configured with several options.
167
175
 
168
176
  | Option | Default | Description |
@@ -185,7 +193,6 @@ export default authkitMiddleware({
185
193
  });
186
194
 
187
195
  // Match against pages that require auth
188
- // Leave this out if you want auth on every resource (including images, css etc.)
189
196
  export const config = { matcher: ['/', '/admin'] };
190
197
  ```
191
198
 
@@ -3,7 +3,7 @@ import { NextRequest } from 'next/server';
3
3
  import { AuthkitMiddlewareAuth, AuthkitOptions, AuthkitResponse, NoUserInfo, Session, UserInfo } from './interfaces.js';
4
4
  import type { AuthenticationResponse } from '@workos-inc/node';
5
5
  declare function encryptSession(session: Session): Promise<string>;
6
- declare function updateSessionMiddleware(request: NextRequest, debug: boolean, middlewareAuth: AuthkitMiddlewareAuth, redirectUri: string, signUpPaths: string[], eagerAuth?: boolean): Promise<import("next/server").NextResponse<unknown>>;
6
+ declare function updateSessionMiddleware(request: NextRequest, debug: boolean, middlewareAuth: AuthkitMiddlewareAuth, redirectUri: string, signUpPaths: string[], eagerAuth?: boolean): Promise<import("next/server.js").NextResponse<unknown>>;
7
7
  declare function updateSession(request: NextRequest, options?: AuthkitOptions): Promise<AuthkitResponse>;
8
8
  declare function refreshSession(options: {
9
9
  organizationId?: string;
@@ -1 +1 @@
1
- export declare function validateApiKey(): Promise<import("@workos-inc/node/lib/api-keys/interfaces/validate-api-key.interface.js").ValidateApiKeyResponse>;
1
+ export declare function validateApiKey(): Promise<import("@workos-inc/node").ValidateApiKeyResponse>;
@@ -1,5 +1,5 @@
1
1
  import { WorkOS } from '@workos-inc/node';
2
- export declare const VERSION = "2.13.0";
2
+ export declare const VERSION = "2.14.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.13.0';
4
+ export const VERSION = '2.14.0';
5
5
  const options = {
6
6
  apiHostname: WORKOS_API_HOSTNAME,
7
7
  https: WORKOS_API_HTTPS ? WORKOS_API_HTTPS === 'true' : true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos-inc/authkit-nextjs",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "Authentication and session helpers for using WorkOS & AuthKit with Next.js",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -22,20 +22,8 @@
22
22
  "import": "./dist/esm/index.js"
23
23
  }
24
24
  },
25
- "scripts": {
26
- "clean": "rm -rf dist",
27
- "prebuild": "npm run clean",
28
- "build": "tsc --project tsconfig.json",
29
- "prepublishOnly": "npm run lint",
30
- "lint": "eslint \"src/**/*.ts*\"",
31
- "test": "jest",
32
- "test:watch": "jest --watch",
33
- "prettier": "prettier \"src/**/*.{js,ts,tsx}\" --check",
34
- "format": "prettier \"src/**/*.{js,ts,tsx}\" --write",
35
- "type-check": "tsc --project tsconfig.json --noEmit"
36
- },
37
25
  "dependencies": {
38
- "@workos-inc/node": "^7.72.0",
26
+ "@workos-inc/node": "^8.2.0",
39
27
  "iron-session": "^8.0.1",
40
28
  "jose": "^5.2.3",
41
29
  "path-to-regexp": "^6.2.2"
@@ -48,21 +36,20 @@
48
36
  "devDependencies": {
49
37
  "@testing-library/jest-dom": "^6.6.3",
50
38
  "@testing-library/react": "^16.0.1",
51
- "@types/jest": "^29.5.14",
52
39
  "@types/node": "^20.11.28",
53
40
  "@types/react": "18.2.67",
54
41
  "@types/react-dom": "18.2.22",
42
+ "@vitest/coverage-v8": "^3.0.0",
55
43
  "eslint": "^8.29.0",
56
44
  "eslint-config-prettier": "^9.1.0",
57
45
  "eslint-plugin-require-extensions": "^0.1.3",
58
- "jest": "^29.7.0",
59
- "jest-environment-jsdom": "^29.7.0",
46
+ "jsdom": "^26.0.0",
60
47
  "next": "^16.0.10",
61
48
  "prettier": "^3.3.3",
62
- "ts-jest": "^29.2.5",
63
- "ts-node": "^10.9.2",
49
+ "tslib": "^2.8.1",
64
50
  "typescript": "5.4.2",
65
- "typescript-eslint": "^7.2.0"
51
+ "typescript-eslint": "^7.2.0",
52
+ "vitest": "^3.0.0"
66
53
  },
67
54
  "license": "MIT",
68
55
  "homepage": "https://github.com/workos/authkit-nextjs#readme",
@@ -72,5 +59,17 @@
72
59
  },
73
60
  "bugs": {
74
61
  "url": "https://github.com/workos/authkit-nextjs/issues"
62
+ },
63
+ "scripts": {
64
+ "clean": "rm -rf dist",
65
+ "prebuild": "pnpm run clean",
66
+ "build": "tsc --project tsconfig.json",
67
+ "lint": "eslint \"src/**/*.ts*\"",
68
+ "test": "vitest run",
69
+ "test:watch": "vitest",
70
+ "test:coverage": "vitest run --coverage",
71
+ "prettier": "prettier \"src/**/*.{js,ts,tsx}\" --check",
72
+ "format": "prettier \"src/**/*.{js,ts,tsx}\" --write",
73
+ "typecheck": "tsc --project tsconfig.json --noEmit"
75
74
  }
76
- }
75
+ }
@@ -12,23 +12,25 @@ import { signOut, switchToOrganization } from './auth.js';
12
12
  import { getWorkOS } from '../src/workos.js';
13
13
  import { withAuth, refreshSession } from '../src/session.js';
14
14
 
15
- jest.mock('../src/auth.js', () => ({
16
- signOut: jest.fn().mockResolvedValue(true),
17
- switchToOrganization: jest.fn().mockResolvedValue({ organizationId: 'org_123' }),
15
+ vi.mock('../src/auth.js', () => ({
16
+ signOut: vi.fn().mockResolvedValue(true),
17
+ switchToOrganization: vi.fn().mockResolvedValue({ organizationId: 'org_123' }),
18
18
  }));
19
19
 
20
- const fakeWorkosInstance = {
21
- organizations: {
22
- getOrganization: jest.fn().mockResolvedValue({ id: 'org_123', name: 'Test Org' }),
20
+ const { fakeWorkosInstance } = vi.hoisted(() => ({
21
+ fakeWorkosInstance: {
22
+ organizations: {
23
+ getOrganization: vi.fn().mockResolvedValue({ id: 'org_123', name: 'Test Org' }),
24
+ },
23
25
  },
24
- };
25
- jest.mock('../src/workos.js', () => ({
26
- getWorkOS: jest.fn(() => fakeWorkosInstance),
26
+ }));
27
+ vi.mock('../src/workos.js', () => ({
28
+ getWorkOS: vi.fn(() => fakeWorkosInstance),
27
29
  }));
28
30
 
29
- jest.mock('../src/session.js', () => ({
30
- withAuth: jest.fn().mockResolvedValue({ user: 'testUser', accessToken: 'access_token' }),
31
- refreshSession: jest.fn().mockResolvedValue({ session: 'newSession', accessToken: 'refreshed_token' }),
31
+ vi.mock('../src/session.js', () => ({
32
+ withAuth: vi.fn().mockResolvedValue({ user: 'testUser', accessToken: 'access_token' }),
33
+ refreshSession: vi.fn().mockResolvedValue({ session: 'newSession', accessToken: 'refreshed_token' }),
32
34
  }));
33
35
 
34
36
  describe('actions', () => {
package/src/auth.spec.ts CHANGED
@@ -1,11 +1,9 @@
1
- import { describe, it, expect, beforeEach, jest } from '@jest/globals';
2
-
3
1
  import { getSignInUrl, getSignUpUrl, signOut, switchToOrganization } from './auth.js';
4
2
  import * as session from './session.js';
5
3
  import * as cache from 'next/cache';
6
4
  import * as workosModule from './workos.js';
7
5
 
8
- // These are mocked in jest.setup.ts
6
+ // These are mocked in vitest.setup.ts
9
7
  import { cookies, headers } from 'next/headers';
10
8
  import { redirect } from 'next/navigation';
11
9
  import { generateSession, generateTestToken } from './test-helpers.js';
@@ -14,44 +12,44 @@ import { getWorkOS } from './workos.js';
14
12
 
15
13
  const workos = getWorkOS();
16
14
 
17
- jest.mock('next/cache', () => {
18
- const actual = jest.requireActual<typeof cache>('next/cache');
15
+ vi.mock('next/cache', async () => {
16
+ const actual = await vi.importActual<typeof cache>('next/cache');
19
17
  return {
20
18
  ...actual,
21
- revalidateTag: jest.fn(),
22
- revalidatePath: jest.fn(),
19
+ revalidateTag: vi.fn(),
20
+ revalidatePath: vi.fn(),
23
21
  };
24
22
  });
25
23
 
26
24
  // Create a fake WorkOS instance that will be used only in the "on error" tests
27
25
  const fakeWorkosInstance = {
28
26
  userManagement: {
29
- authenticateWithRefreshToken: jest.fn(),
30
- getAuthorizationUrl: jest.fn(),
31
- getJwksUrl: jest.fn(() => 'https://api.workos.com/sso/jwks/client_1234567890'),
32
- getLogoutUrl: jest.fn(),
27
+ authenticateWithRefreshToken: vi.fn(),
28
+ getAuthorizationUrl: vi.fn(),
29
+ getJwksUrl: vi.fn(() => 'https://api.workos.com/sso/jwks/client_1234567890'),
30
+ getLogoutUrl: vi.fn(),
33
31
  },
34
32
  };
35
33
 
36
- const revalidatePath = jest.mocked(cache.revalidatePath);
37
- const revalidateTag = jest.mocked(cache.revalidateTag);
34
+ const revalidatePath = vi.mocked(cache.revalidatePath);
35
+ const revalidateTag = vi.mocked(cache.revalidateTag);
38
36
  // We'll only use these in the "on error" tests
39
37
  const authenticateWithRefreshToken = fakeWorkosInstance.userManagement.authenticateWithRefreshToken;
40
38
  const getAuthorizationUrl = fakeWorkosInstance.userManagement.getAuthorizationUrl;
41
39
 
42
- jest.mock('../src/session', () => {
43
- const actual = jest.requireActual<typeof session>('../src/session');
40
+ vi.mock('../src/session', async () => {
41
+ const actual = await vi.importActual<typeof session>('../src/session');
44
42
 
45
43
  return {
46
44
  ...actual,
47
- refreshSession: jest.fn(actual.refreshSession),
45
+ refreshSession: vi.fn(actual.refreshSession),
48
46
  };
49
47
  });
50
48
 
51
49
  describe('auth.ts', () => {
52
50
  beforeEach(async () => {
53
51
  // Clear all mocks between tests
54
- jest.clearAllMocks();
52
+ vi.clearAllMocks();
55
53
 
56
54
  // Reset the cookie store
57
55
  const nextCookies = await cookies();
@@ -139,10 +137,10 @@ describe('auth.ts', () => {
139
137
  const mockWorkOS = {
140
138
  userManagement: fakeWorkosInstance.userManagement,
141
139
  // Add minimal properties to satisfy TypeScript
142
- createHttpClient: jest.fn(),
143
- createWebhookClient: jest.fn(),
144
- createActionsClient: jest.fn(),
145
- createIronSessionProvider: jest.fn(),
140
+ createHttpClient: vi.fn(),
141
+ createWebhookClient: vi.fn(),
142
+ createActionsClient: vi.fn(),
143
+ createIronSessionProvider: vi.fn(),
146
144
  apiKey: 'test',
147
145
  clientId: 'test',
148
146
  host: 'test',
@@ -154,12 +152,12 @@ describe('auth.ts', () => {
154
152
 
155
153
  // Apply the mock for these tests only
156
154
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
157
- jest.spyOn(workosModule, 'getWorkOS').mockImplementation(() => mockWorkOS as any);
155
+ vi.spyOn(workosModule, 'getWorkOS').mockImplementation(() => mockWorkOS as any);
158
156
  });
159
157
 
160
158
  afterEach(() => {
161
159
  // Restore all mocks after each test
162
- jest.restoreAllMocks();
160
+ vi.restoreAllMocks();
163
161
  });
164
162
 
165
163
  it('should redirect to sign in when error is "sso_required"', async () => {
@@ -245,9 +243,9 @@ describe('auth.ts', () => {
245
243
 
246
244
  describe('when given a `returnTo` parameter', () => {
247
245
  it('passes the `returnTo` through to the `getLogoutUrl` call', async () => {
248
- jest
249
- .spyOn(workos.userManagement, 'getLogoutUrl')
250
- .mockReturnValue('https://user-management-logout.com/signed-out');
246
+ vi.spyOn(workos.userManagement, 'getLogoutUrl').mockReturnValue(
247
+ 'https://user-management-logout.com/signed-out',
248
+ );
251
249
  const mockSession = {
252
250
  accessToken: await generateTestToken(),
253
251
  sessionId: 'session_123',
@@ -306,9 +304,9 @@ describe('auth.ts', () => {
306
304
 
307
305
  nextCookies.set('wos-session', encryptedSession);
308
306
 
309
- jest
310
- .spyOn(workos.userManagement, 'getLogoutUrl')
311
- .mockReturnValue('https://api.workos.com/user_management/sessions/logout?session_id=session_123');
307
+ vi.spyOn(workos.userManagement, 'getLogoutUrl').mockReturnValue(
308
+ 'https://api.workos.com/user_management/sessions/logout?session_id=session_123',
309
+ );
312
310
 
313
311
  await signOut();
314
312
 
@@ -3,19 +3,21 @@ import { handleAuth } from './authkit-callback-route.js';
3
3
  import { getSessionFromCookie, saveSession } from './session.js';
4
4
  import { NextRequest, NextResponse } from 'next/server';
5
5
 
6
- // Mocked in jest.setup.ts
6
+ // Mocked in vitest.setup.ts
7
7
  import { cookies, headers } from 'next/headers';
8
8
 
9
9
  // Mock dependencies
10
- const fakeWorkosInstance = {
11
- userManagement: {
12
- authenticateWithCode: jest.fn(),
13
- getJwksUrl: jest.fn(() => 'https://api.workos.com/sso/jwks/client_1234567890'),
10
+ const { fakeWorkosInstance } = vi.hoisted(() => ({
11
+ fakeWorkosInstance: {
12
+ userManagement: {
13
+ authenticateWithCode: vi.fn(),
14
+ getJwksUrl: vi.fn(() => 'https://api.workos.com/sso/jwks/client_1234567890'),
15
+ },
14
16
  },
15
- };
17
+ }));
16
18
 
17
- jest.mock('../src/workos', () => ({
18
- getWorkOS: jest.fn(() => fakeWorkosInstance),
19
+ vi.mock('../src/workos', () => ({
20
+ getWorkOS: vi.fn(() => fakeWorkosInstance),
19
21
  }));
20
22
 
21
23
  describe('authkit-callback-route', () => {
@@ -51,12 +53,12 @@ describe('authkit-callback-route', () => {
51
53
 
52
54
  beforeAll(() => {
53
55
  // Silence console.error during tests
54
- jest.spyOn(console, 'error').mockImplementation(() => {});
56
+ vi.spyOn(console, 'error').mockImplementation(() => {});
55
57
  });
56
58
 
57
59
  beforeEach(async () => {
58
60
  // Reset all mocks
59
- jest.clearAllMocks();
61
+ vi.clearAllMocks();
60
62
 
61
63
  // Create a new request with searchParams
62
64
  request = new NextRequest(new URL('http://example.com/callback'));
@@ -72,7 +74,7 @@ describe('authkit-callback-route', () => {
72
74
  });
73
75
 
74
76
  it('should handle successful authentication', async () => {
75
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
77
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
76
78
 
77
79
  // Set up request with code
78
80
  request.nextUrl.searchParams.set('code', 'test-code');
@@ -89,7 +91,7 @@ describe('authkit-callback-route', () => {
89
91
 
90
92
  it('should handle authentication failure', async () => {
91
93
  // Mock authentication failure
92
- (workos.userManagement.authenticateWithCode as jest.Mock).mockRejectedValue(new Error('Auth failed'));
94
+ (workos.userManagement.authenticateWithCode as Mock).mockRejectedValue(new Error('Auth failed'));
93
95
 
94
96
  request.nextUrl.searchParams.set('code', 'invalid-code');
95
97
 
@@ -103,7 +105,7 @@ describe('authkit-callback-route', () => {
103
105
 
104
106
  it('should handle authentication failure if a non-Error object is thrown', async () => {
105
107
  // Mock authentication failure
106
- jest.mocked(workos.userManagement.authenticateWithCode).mockRejectedValue('Auth failed');
108
+ vi.mocked(workos.userManagement.authenticateWithCode).mockRejectedValue('Auth failed');
107
109
 
108
110
  request.nextUrl.searchParams.set('code', 'invalid-code');
109
111
 
@@ -117,7 +119,7 @@ describe('authkit-callback-route', () => {
117
119
 
118
120
  it('should handle authentication failure with custom onError handler', async () => {
119
121
  // Mock authentication failure
120
- jest.mocked(workos.userManagement.authenticateWithCode).mockRejectedValue('Auth failed');
122
+ vi.mocked(workos.userManagement.authenticateWithCode).mockRejectedValue('Auth failed');
121
123
  request.nextUrl.searchParams.set('code', 'invalid-code');
122
124
 
123
125
  const handler = handleAuth({
@@ -145,7 +147,7 @@ describe('authkit-callback-route', () => {
145
147
  });
146
148
 
147
149
  it('should respect custom returnPathname', async () => {
148
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
150
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
149
151
 
150
152
  request.nextUrl.searchParams.set('code', 'test-code');
151
153
 
@@ -156,7 +158,7 @@ describe('authkit-callback-route', () => {
156
158
  });
157
159
 
158
160
  it('should handle state parameter with returnPathname', async () => {
159
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
161
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
160
162
 
161
163
  const state = btoa(JSON.stringify({ returnPathname: '/custom-path' }));
162
164
  request.nextUrl.searchParams.set('code', 'test-code');
@@ -169,7 +171,7 @@ describe('authkit-callback-route', () => {
169
171
  });
170
172
 
171
173
  it('should extract custom search params from returnPathname', async () => {
172
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
174
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
173
175
 
174
176
  const state = btoa(JSON.stringify({ returnPathname: '/custom-path?foo=bar&baz=qux' }));
175
177
  request.nextUrl.searchParams.set('code', 'test-code');
@@ -182,7 +184,7 @@ describe('authkit-callback-route', () => {
182
184
  });
183
185
 
184
186
  it('should handle full URL in returnPathname by extracting only the pathname', async () => {
185
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
187
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
186
188
 
187
189
  const state = btoa(JSON.stringify({ returnPathname: 'https://example.com/invite/k0123456789' }));
188
190
  request.nextUrl.searchParams.set('code', 'test-code');
@@ -200,7 +202,7 @@ describe('authkit-callback-route', () => {
200
202
  const originalRedirect = NextResponse.redirect;
201
203
  (NextResponse as Partial<typeof NextResponse>).redirect = undefined;
202
204
 
203
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
205
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
204
206
 
205
207
  // Set up request with code
206
208
  request.nextUrl.searchParams.set('code', 'test-code');
@@ -232,7 +234,7 @@ describe('authkit-callback-route', () => {
232
234
  });
233
235
 
234
236
  it('should use baseURL if provided', async () => {
235
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
237
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
236
238
 
237
239
  // Set up request with code
238
240
  request.nextUrl.searchParams.set('code', 'test-code');
@@ -248,7 +250,7 @@ describe('authkit-callback-route', () => {
248
250
  user: { id: 'user_123' },
249
251
  };
250
252
 
251
- (workos.userManagement.authenticateWithCode as jest.Mock).mockResolvedValue(mockAuthResponse);
253
+ (workos.userManagement.authenticateWithCode as Mock).mockResolvedValue(mockAuthResponse);
252
254
 
253
255
  // Set up request with code
254
256
  request.nextUrl.searchParams.set('code', 'test-code');
@@ -260,12 +262,12 @@ describe('authkit-callback-route', () => {
260
262
  });
261
263
 
262
264
  it('should call onSuccess if provided', async () => {
263
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
265
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
264
266
 
265
267
  // Set up request with code
266
268
  request.nextUrl.searchParams.set('code', 'test-code');
267
269
 
268
- const onSuccess = jest.fn();
270
+ const onSuccess = vi.fn();
269
271
  const handler = handleAuth({ onSuccess: onSuccess });
270
272
  await handler(request);
271
273
 
@@ -276,7 +278,7 @@ describe('authkit-callback-route', () => {
276
278
 
277
279
  it('should allow onSuccess to update session', async () => {
278
280
  const newAccessToken = 'new-access-token';
279
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
281
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
280
282
 
281
283
  // Set up request with code
282
284
  request.nextUrl.searchParams.set('code', 'test-code');
@@ -293,7 +295,7 @@ describe('authkit-callback-route', () => {
293
295
  });
294
296
 
295
297
  it('should pass custom state data to onSuccess callback', async () => {
296
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
298
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
297
299
 
298
300
  // Create state with new format: internal.user
299
301
  const internalState = btoa(JSON.stringify({ returnPathname: '/dashboard' }))
@@ -305,7 +307,7 @@ describe('authkit-callback-route', () => {
305
307
  request.nextUrl.searchParams.set('code', 'test-code');
306
308
  request.nextUrl.searchParams.set('state', state);
307
309
 
308
- const onSuccess = jest.fn();
310
+ const onSuccess = vi.fn();
309
311
  const handler = handleAuth({ onSuccess });
310
312
  await handler(request);
311
313
 
@@ -323,7 +325,7 @@ describe('authkit-callback-route', () => {
323
325
  });
324
326
 
325
327
  it('should handle state without custom data', async () => {
326
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
328
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
327
329
 
328
330
  // State with only returnPathname
329
331
  const state = btoa(JSON.stringify({ returnPathname: '/profile' }));
@@ -331,7 +333,7 @@ describe('authkit-callback-route', () => {
331
333
  request.nextUrl.searchParams.set('code', 'test-code');
332
334
  request.nextUrl.searchParams.set('state', state);
333
335
 
334
- const onSuccess = jest.fn();
336
+ const onSuccess = vi.fn();
335
337
  const handler = handleAuth({ onSuccess });
336
338
  await handler(request);
337
339
 
@@ -345,7 +347,7 @@ describe('authkit-callback-route', () => {
345
347
  });
346
348
 
347
349
  it('should handle backward compatibility with old state format', async () => {
348
- jest.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
350
+ vi.mocked(workos.userManagement.authenticateWithCode).mockResolvedValue(mockAuthResponse);
349
351
 
350
352
  // Old format: just returnPathname
351
353
  const state = btoa(JSON.stringify({ returnPathname: '/old-path' }));