@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 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
 
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({ organizationId, screenHint: 'sign-in', loginHint, redirectUri, prompt, state });
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({ organizationId, screenHint: 'sign-up', loginHint, redirectUri, prompt, state });
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.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
@@ -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/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.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": "^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();
@@ -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: jest.fn(),
143
- createWebhookClient: jest.fn(),
144
- createActionsClient: jest.fn(),
145
- createIronSessionProvider: jest.fn(),
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
- jest.spyOn(workosModule, 'getWorkOS').mockImplementation(() => mockWorkOS as any);
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
- jest.restoreAllMocks();
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
- jest
249
- .spyOn(workos.userManagement, 'getLogoutUrl')
250
- .mockReturnValue('https://user-management-logout.com/signed-out');
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
- jest
310
- .spyOn(workos.userManagement, 'getLogoutUrl')
311
- .mockReturnValue('https://api.workos.com/user_management/sessions/logout?session_id=session_123');
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({ organizationId, screenHint: 'sign-in', loginHint, redirectUri, prompt, state });
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({ organizationId, screenHint: 'sign-up', loginHint, redirectUri, prompt, state });
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
  /**