@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 +10 -3
- package/dist/esm/types/session.d.ts +1 -1
- package/dist/esm/types/validate-api-key.d.ts +1 -1
- package/dist/esm/types/workos.d.ts +1 -1
- package/dist/esm/workos.js +1 -1
- package/package.json +20 -21
- package/src/actions.spec.ts +14 -12
- package/src/auth.spec.ts +27 -29
- package/src/authkit-callback-route.spec.ts +31 -29
- package/src/components/authkit-provider.spec.tsx +31 -31
- package/src/components/button.spec.tsx +4 -6
- package/src/components/impersonation.spec.tsx +25 -25
- package/src/components/min-max-button.spec.tsx +2 -2
- package/src/components/tokenStore.spec.ts +21 -21
- package/src/components/useAccessToken.spec.tsx +73 -77
- package/src/components/useTokenClaims.spec.tsx +22 -22
- package/src/cookie.spec.ts +7 -8
- package/src/get-authorization-url.spec.ts +12 -13
- package/src/session.spec.ts +74 -63
- package/src/utils.spec.ts +14 -31
- package/src/validate-api-key.spec.ts +4 -6
- package/src/workos.spec.ts +2 -2
- package/src/workos.ts +1 -1
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
|
-
|
|
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
|
|
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.
|
|
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.
|
package/dist/esm/workos.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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": "^
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
+
}
|
package/src/actions.spec.ts
CHANGED
|
@@ -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
|
-
|
|
16
|
-
signOut:
|
|
17
|
-
switchToOrganization:
|
|
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
|
-
|
|
22
|
-
|
|
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
|
-
|
|
26
|
-
getWorkOS:
|
|
26
|
+
}));
|
|
27
|
+
vi.mock('../src/workos.js', () => ({
|
|
28
|
+
getWorkOS: vi.fn(() => fakeWorkosInstance),
|
|
27
29
|
}));
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
withAuth:
|
|
31
|
-
refreshSession:
|
|
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
|
|
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
|
-
|
|
18
|
-
const actual =
|
|
15
|
+
vi.mock('next/cache', async () => {
|
|
16
|
+
const actual = await vi.importActual<typeof cache>('next/cache');
|
|
19
17
|
return {
|
|
20
18
|
...actual,
|
|
21
|
-
revalidateTag:
|
|
22
|
-
revalidatePath:
|
|
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:
|
|
30
|
-
getAuthorizationUrl:
|
|
31
|
-
getJwksUrl:
|
|
32
|
-
getLogoutUrl:
|
|
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 =
|
|
37
|
-
const 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
|
-
|
|
43
|
-
const actual =
|
|
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:
|
|
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
|
-
|
|
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:
|
|
143
|
-
createWebhookClient:
|
|
144
|
-
createActionsClient:
|
|
145
|
-
createIronSessionProvider:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
249
|
-
.
|
|
250
|
-
|
|
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
|
-
|
|
310
|
-
.
|
|
311
|
-
|
|
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
|
|
6
|
+
// Mocked in vitest.setup.ts
|
|
7
7
|
import { cookies, headers } from 'next/headers';
|
|
8
8
|
|
|
9
9
|
// Mock dependencies
|
|
10
|
-
const fakeWorkosInstance = {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
18
|
-
getWorkOS:
|
|
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
|
-
|
|
56
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
beforeEach(async () => {
|
|
58
60
|
// Reset all mocks
|
|
59
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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' }));
|