@workos-inc/authkit-nextjs 2.13.0 → 2.15.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/auth.js +20 -4
- package/dist/esm/auth.js.map +1 -1
- package/dist/esm/types/auth.d.ts +4 -2
- 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 +45 -29
- package/src/auth.ts +22 -2
- 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
|
|
package/dist/esm/auth.js
CHANGED
|
@@ -16,11 +16,27 @@ function revalidateTagCompat(tag) {
|
|
|
16
16
|
const fn = revalidateTag;
|
|
17
17
|
return fn(tag, 'max');
|
|
18
18
|
}
|
|
19
|
-
export async function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, state, } = {}) {
|
|
20
|
-
return getAuthorizationUrl({
|
|
19
|
+
export async function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, state, returnTo, } = {}) {
|
|
20
|
+
return getAuthorizationUrl({
|
|
21
|
+
organizationId,
|
|
22
|
+
screenHint: 'sign-in',
|
|
23
|
+
loginHint,
|
|
24
|
+
redirectUri,
|
|
25
|
+
prompt,
|
|
26
|
+
state,
|
|
27
|
+
returnPathname: returnTo,
|
|
28
|
+
});
|
|
21
29
|
}
|
|
22
|
-
export async function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, state, } = {}) {
|
|
23
|
-
return getAuthorizationUrl({
|
|
30
|
+
export async function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, state, returnTo, } = {}) {
|
|
31
|
+
return getAuthorizationUrl({
|
|
32
|
+
organizationId,
|
|
33
|
+
screenHint: 'sign-up',
|
|
34
|
+
loginHint,
|
|
35
|
+
redirectUri,
|
|
36
|
+
prompt,
|
|
37
|
+
state,
|
|
38
|
+
returnPathname: returnTo,
|
|
39
|
+
});
|
|
24
40
|
}
|
|
25
41
|
/**
|
|
26
42
|
* Sign out the user and delete the session cookie.
|
package/dist/esm/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC;;;GAGG;AACH,SAAS,mBAAmB,CAAC,GAAW;IACtC,MAAM,EAAE,GAAG,aAAuD,CAAC;IACnE,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EACjC,cAAc,EACd,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/types/auth.d.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import type { SwitchToOrganizationOptions, UserInfo } from './interfaces.js';
|
|
2
|
-
export declare function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, state, }?: {
|
|
2
|
+
export declare function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, state, returnTo, }?: {
|
|
3
3
|
organizationId?: string;
|
|
4
4
|
loginHint?: string;
|
|
5
5
|
redirectUri?: string;
|
|
6
6
|
prompt?: 'consent';
|
|
7
7
|
state?: string;
|
|
8
|
+
returnTo?: string;
|
|
8
9
|
}): Promise<string>;
|
|
9
|
-
export declare function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, state, }?: {
|
|
10
|
+
export declare function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, state, returnTo, }?: {
|
|
10
11
|
organizationId?: string;
|
|
11
12
|
loginHint?: string;
|
|
12
13
|
redirectUri?: string;
|
|
13
14
|
prompt?: 'consent';
|
|
14
15
|
state?: string;
|
|
16
|
+
returnTo?: string;
|
|
15
17
|
}): Promise<string>;
|
|
16
18
|
/**
|
|
17
19
|
* Sign out the user and delete the session cookie.
|
|
@@ -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.15.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();
|
|
@@ -76,6 +74,15 @@ describe('auth.ts', () => {
|
|
|
76
74
|
expect(url).toBeDefined();
|
|
77
75
|
expect(() => new URL(url)).not.toThrow();
|
|
78
76
|
});
|
|
77
|
+
|
|
78
|
+
it('should include returnTo as returnPathname in the state parameter', async () => {
|
|
79
|
+
const url = await getSignInUrl({ returnTo: '/dashboard' });
|
|
80
|
+
const parsedUrl = new URL(url);
|
|
81
|
+
const state = parsedUrl.searchParams.get('state');
|
|
82
|
+
expect(state).toBeDefined();
|
|
83
|
+
const decoded = JSON.parse(atob(state!.replace(/-/g, '+').replace(/_/g, '/')));
|
|
84
|
+
expect(decoded.returnPathname).toBe('/dashboard');
|
|
85
|
+
});
|
|
79
86
|
});
|
|
80
87
|
|
|
81
88
|
it('should not include prompt when not specified for getSignInUrl', async () => {
|
|
@@ -103,6 +110,15 @@ describe('auth.ts', () => {
|
|
|
103
110
|
const url = await getSignUpUrl({ prompt: 'consent' });
|
|
104
111
|
expect(url).toContain('prompt=consent');
|
|
105
112
|
});
|
|
113
|
+
|
|
114
|
+
it('should include returnTo as returnPathname in the state parameter', async () => {
|
|
115
|
+
const url = await getSignUpUrl({ returnTo: '/welcome' });
|
|
116
|
+
const parsedUrl = new URL(url);
|
|
117
|
+
const state = parsedUrl.searchParams.get('state');
|
|
118
|
+
expect(state).toBeDefined();
|
|
119
|
+
const decoded = JSON.parse(atob(state!.replace(/-/g, '+').replace(/_/g, '/')));
|
|
120
|
+
expect(decoded.returnPathname).toBe('/welcome');
|
|
121
|
+
});
|
|
106
122
|
});
|
|
107
123
|
|
|
108
124
|
describe('switchToOrganization', () => {
|
|
@@ -139,10 +155,10 @@ describe('auth.ts', () => {
|
|
|
139
155
|
const mockWorkOS = {
|
|
140
156
|
userManagement: fakeWorkosInstance.userManagement,
|
|
141
157
|
// Add minimal properties to satisfy TypeScript
|
|
142
|
-
createHttpClient:
|
|
143
|
-
createWebhookClient:
|
|
144
|
-
createActionsClient:
|
|
145
|
-
createIronSessionProvider:
|
|
158
|
+
createHttpClient: vi.fn(),
|
|
159
|
+
createWebhookClient: vi.fn(),
|
|
160
|
+
createActionsClient: vi.fn(),
|
|
161
|
+
createIronSessionProvider: vi.fn(),
|
|
146
162
|
apiKey: 'test',
|
|
147
163
|
clientId: 'test',
|
|
148
164
|
host: 'test',
|
|
@@ -154,12 +170,12 @@ describe('auth.ts', () => {
|
|
|
154
170
|
|
|
155
171
|
// Apply the mock for these tests only
|
|
156
172
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
157
|
-
|
|
173
|
+
vi.spyOn(workosModule, 'getWorkOS').mockImplementation(() => mockWorkOS as any);
|
|
158
174
|
});
|
|
159
175
|
|
|
160
176
|
afterEach(() => {
|
|
161
177
|
// Restore all mocks after each test
|
|
162
|
-
|
|
178
|
+
vi.restoreAllMocks();
|
|
163
179
|
});
|
|
164
180
|
|
|
165
181
|
it('should redirect to sign in when error is "sso_required"', async () => {
|
|
@@ -245,9 +261,9 @@ describe('auth.ts', () => {
|
|
|
245
261
|
|
|
246
262
|
describe('when given a `returnTo` parameter', () => {
|
|
247
263
|
it('passes the `returnTo` through to the `getLogoutUrl` call', async () => {
|
|
248
|
-
|
|
249
|
-
.
|
|
250
|
-
|
|
264
|
+
vi.spyOn(workos.userManagement, 'getLogoutUrl').mockReturnValue(
|
|
265
|
+
'https://user-management-logout.com/signed-out',
|
|
266
|
+
);
|
|
251
267
|
const mockSession = {
|
|
252
268
|
accessToken: await generateTestToken(),
|
|
253
269
|
sessionId: 'session_123',
|
|
@@ -306,9 +322,9 @@ describe('auth.ts', () => {
|
|
|
306
322
|
|
|
307
323
|
nextCookies.set('wos-session', encryptedSession);
|
|
308
324
|
|
|
309
|
-
|
|
310
|
-
.
|
|
311
|
-
|
|
325
|
+
vi.spyOn(workos.userManagement, 'getLogoutUrl').mockReturnValue(
|
|
326
|
+
'https://api.workos.com/user_management/sessions/logout?session_id=session_123',
|
|
327
|
+
);
|
|
312
328
|
|
|
313
329
|
await signOut();
|
|
314
330
|
|
package/src/auth.ts
CHANGED
|
@@ -26,14 +26,24 @@ export async function getSignInUrl({
|
|
|
26
26
|
redirectUri,
|
|
27
27
|
prompt,
|
|
28
28
|
state,
|
|
29
|
+
returnTo,
|
|
29
30
|
}: {
|
|
30
31
|
organizationId?: string;
|
|
31
32
|
loginHint?: string;
|
|
32
33
|
redirectUri?: string;
|
|
33
34
|
prompt?: 'consent';
|
|
34
35
|
state?: string;
|
|
36
|
+
returnTo?: string;
|
|
35
37
|
} = {}) {
|
|
36
|
-
return getAuthorizationUrl({
|
|
38
|
+
return getAuthorizationUrl({
|
|
39
|
+
organizationId,
|
|
40
|
+
screenHint: 'sign-in',
|
|
41
|
+
loginHint,
|
|
42
|
+
redirectUri,
|
|
43
|
+
prompt,
|
|
44
|
+
state,
|
|
45
|
+
returnPathname: returnTo,
|
|
46
|
+
});
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
export async function getSignUpUrl({
|
|
@@ -42,14 +52,24 @@ export async function getSignUpUrl({
|
|
|
42
52
|
redirectUri,
|
|
43
53
|
prompt,
|
|
44
54
|
state,
|
|
55
|
+
returnTo,
|
|
45
56
|
}: {
|
|
46
57
|
organizationId?: string;
|
|
47
58
|
loginHint?: string;
|
|
48
59
|
redirectUri?: string;
|
|
49
60
|
prompt?: 'consent';
|
|
50
61
|
state?: string;
|
|
62
|
+
returnTo?: string;
|
|
51
63
|
} = {}) {
|
|
52
|
-
return getAuthorizationUrl({
|
|
64
|
+
return getAuthorizationUrl({
|
|
65
|
+
organizationId,
|
|
66
|
+
screenHint: 'sign-up',
|
|
67
|
+
loginHint,
|
|
68
|
+
redirectUri,
|
|
69
|
+
prompt,
|
|
70
|
+
state,
|
|
71
|
+
returnPathname: returnTo,
|
|
72
|
+
});
|
|
53
73
|
}
|
|
54
74
|
|
|
55
75
|
/**
|