@workos-inc/authkit-nextjs 2.17.0 → 3.0.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 +40 -11
- package/dist/esm/actions.js +35 -4
- package/dist/esm/actions.js.map +1 -1
- package/dist/esm/auth.js +13 -22
- package/dist/esm/auth.js.map +1 -1
- package/dist/esm/authkit-callback-route.js +71 -95
- package/dist/esm/authkit-callback-route.js.map +1 -1
- package/dist/esm/components/authkit-provider.js +31 -13
- package/dist/esm/components/authkit-provider.js.map +1 -1
- package/dist/esm/components/impersonation.js +9 -9
- package/dist/esm/components/impersonation.js.map +1 -1
- package/dist/esm/components/min-max-button.js +1 -1
- package/dist/esm/components/min-max-button.js.map +1 -1
- package/dist/esm/components/tokenStore.js +28 -19
- package/dist/esm/components/tokenStore.js.map +1 -1
- package/dist/esm/components/useAccessToken.js +1 -1
- package/dist/esm/components/useAccessToken.js.map +1 -1
- package/dist/esm/components/useTokenClaims.js +1 -1
- package/dist/esm/components/useTokenClaims.js.map +1 -1
- package/dist/esm/cookie.js +16 -5
- package/dist/esm/cookie.js.map +1 -1
- package/dist/esm/env-variables.js +5 -7
- package/dist/esm/env-variables.js.map +1 -1
- package/dist/esm/errors.js +7 -4
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/get-authorization-url.js +23 -27
- package/dist/esm/get-authorization-url.js.map +1 -1
- package/dist/esm/index.js +3 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interfaces.js +7 -1
- package/dist/esm/interfaces.js.map +1 -1
- package/dist/esm/middleware-helpers.js +8 -5
- package/dist/esm/middleware-helpers.js.map +1 -1
- package/dist/esm/middleware.js +3 -1
- package/dist/esm/middleware.js.map +1 -1
- package/dist/esm/pkce.js +17 -22
- package/dist/esm/pkce.js.map +1 -1
- package/dist/esm/session.js +19 -23
- package/dist/esm/session.js.map +1 -1
- package/dist/esm/types/actions.d.ts +34 -5
- package/dist/esm/types/auth.d.ts +6 -16
- package/dist/esm/types/cookie.d.ts +8 -0
- package/dist/esm/types/env-variables.d.ts +1 -2
- package/dist/esm/types/get-authorization-url.d.ts +1 -1
- package/dist/esm/types/index.d.ts +3 -3
- package/dist/esm/types/interfaces.d.ts +9 -1
- package/dist/esm/types/jwt.d.ts +9 -9
- package/dist/esm/types/middleware-helpers.d.ts +3 -1
- package/dist/esm/types/middleware.d.ts +3 -1
- package/dist/esm/types/pkce.d.ts +6 -5
- package/dist/esm/utils.js +2 -2
- package/dist/esm/utils.js.map +1 -1
- package/dist/esm/validate-api-key.js +1 -2
- package/dist/esm/validate-api-key.js.map +1 -1
- package/package.json +12 -13
- package/src/actions.spec.ts +81 -6
- package/src/actions.ts +44 -5
- package/src/auth.spec.ts +3 -2
- package/src/auth.ts +12 -43
- package/src/authkit-callback-route.spec.ts +210 -60
- package/src/authkit-callback-route.ts +94 -107
- package/src/components/authkit-provider.spec.tsx +89 -6
- package/src/components/authkit-provider.tsx +20 -1
- package/src/components/impersonation.spec.tsx +1 -0
- package/src/components/impersonation.tsx +29 -24
- package/src/components/tokenStore.spec.ts +35 -20
- package/src/components/tokenStore.ts +11 -3
- package/src/components/useAccessToken.spec.tsx +15 -12
- package/src/components/useTokenClaims.spec.tsx +1 -0
- package/src/cookie.ts +29 -0
- package/src/env-variables.ts +0 -2
- package/src/get-authorization-url.spec.ts +18 -40
- package/src/get-authorization-url.ts +34 -40
- package/src/index.ts +3 -1
- package/src/interfaces.ts +11 -1
- package/src/jwt.ts +9 -9
- package/src/middleware-helpers.spec.ts +7 -0
- package/src/middleware-helpers.ts +7 -3
- package/src/middleware.spec.ts +25 -0
- package/src/middleware.ts +4 -1
- package/src/pkce.spec.ts +125 -0
- package/src/pkce.ts +19 -19
- package/src/session.spec.ts +18 -22
- package/src/session.ts +10 -12
package/README.md
CHANGED
|
@@ -56,7 +56,6 @@ Certain environment variables are optional and can be used to debug or configure
|
|
|
56
56
|
| `WORKOS_API_HTTPS` | `true` | Whether to use HTTPS in API calls |
|
|
57
57
|
| `WORKOS_API_PORT` | None | Port to use for API calls. When not set, uses standard ports (443 for HTTPS, 80 for HTTP) |
|
|
58
58
|
| `WORKOS_COOKIE_SAMESITE` | `'lax'` | SameSite attribute for cookies. Options: `'lax'`, `'strict'`, or `'none'` |
|
|
59
|
-
| `WORKOS_DISABLE_PKCE` | None | Set to `'true'` to disable PKCE on authorization requests |
|
|
60
59
|
|
|
61
60
|
Example usage:
|
|
62
61
|
|
|
@@ -150,14 +149,21 @@ This library relies on Next.js proxy (called "middleware" in Next.js ≤15) to p
|
|
|
150
149
|
**For Next.js 16+:** Create a `proxy.ts` file in the root of your project.
|
|
151
150
|
**For Next.js ≤15:** Create a `middleware.ts` file in the root of your project.
|
|
152
151
|
|
|
153
|
-
|
|
152
|
+
```ts
|
|
153
|
+
// proxy.ts (Next.js 16+)
|
|
154
|
+
import { authkitProxy } from '@workos-inc/authkit-nextjs';
|
|
155
|
+
|
|
156
|
+
export default authkitProxy();
|
|
157
|
+
|
|
158
|
+
// Match against pages that require auth
|
|
159
|
+
export const config = { matcher: ['/', '/admin'] };
|
|
160
|
+
```
|
|
154
161
|
|
|
155
162
|
```ts
|
|
156
|
-
//
|
|
163
|
+
// middleware.ts (Next.js ≤15)
|
|
157
164
|
import { authkitMiddleware } from '@workos-inc/authkit-nextjs';
|
|
158
165
|
|
|
159
166
|
export default authkitMiddleware();
|
|
160
|
-
// For Next.js 16+, you can also use: export { default as proxy } from './proxy';
|
|
161
167
|
|
|
162
168
|
// Match against pages that require auth
|
|
163
169
|
export const config = { matcher: ['/', '/admin'] };
|
|
@@ -689,16 +695,18 @@ import { useAccessToken } from '@workos-inc/authkit-nextjs/components';
|
|
|
689
695
|
function MyComponent() {
|
|
690
696
|
const { getAccessToken } = useAccessToken();
|
|
691
697
|
|
|
692
|
-
|
|
693
|
-
|
|
698
|
+
async function handleClick() {
|
|
699
|
+
// Token is available immediately on initial page load
|
|
700
|
+
const token = await getAccessToken();
|
|
694
701
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
702
|
+
// Use with third-party services that need immediate token access
|
|
703
|
+
if (token) {
|
|
704
|
+
// Initialize your third-party client with the token
|
|
705
|
+
thirdPartyClient.authenticate(token);
|
|
706
|
+
}
|
|
699
707
|
}
|
|
700
708
|
|
|
701
|
-
return <
|
|
709
|
+
return <button onClick={handleClick}>Authenticate</button>;
|
|
702
710
|
}
|
|
703
711
|
```
|
|
704
712
|
|
|
@@ -908,6 +916,27 @@ import { authkitMiddleware } from '@workos-inc/authkit-nextjs';
|
|
|
908
916
|
export default authkitMiddleware({ debug: true });
|
|
909
917
|
```
|
|
910
918
|
|
|
919
|
+
### Security
|
|
920
|
+
|
|
921
|
+
#### PKCE and CSRF protection
|
|
922
|
+
|
|
923
|
+
This library uses [PKCE](https://datatracker.ietf.org/doc/html/rfc7636) (Proof Key for Code Exchange) and a sealed (encrypted) OAuth state parameter on every authorization request. The state contains a cryptographic nonce for CSRF protection per [RFC 9700](https://datatracker.ietf.org/doc/rfc9700/) and a code verifier for protection against authorization code interception. During sign-in, a short-lived `wos-auth-verifier` cookie is set containing the sealed state. This cookie is automatically cleaned up after the callback completes.
|
|
924
|
+
|
|
925
|
+
> [!NOTE]
|
|
926
|
+
> **Upgrading to v3:** PKCE is now always enabled. The `WORKOS_ENABLE_PKCE` environment variable is no longer needed and can be removed from your configuration.
|
|
927
|
+
|
|
928
|
+
#### Cookie requirements
|
|
929
|
+
|
|
930
|
+
The `wos-auth-verifier` cookie must survive the round-trip from sign-in initiation to the callback. On callback, the library verifies that the cookie is present and matches the URL `state` parameter — this two-channel check is what prevents CSRF attacks.
|
|
931
|
+
|
|
932
|
+
If the cookie is missing or doesn't match, authentication will fail with one of:
|
|
933
|
+
|
|
934
|
+
- `Auth cookie missing` — the cookie was not sent back with the callback request. This typically happens when a reverse proxy or CDN strips `Set-Cookie` headers on redirects.
|
|
935
|
+
- `OAuth state mismatch` — the cookie and URL `state` parameter don't match, indicating a possible CSRF attack or cookie corruption.
|
|
936
|
+
|
|
937
|
+
> [!IMPORTANT]
|
|
938
|
+
> **Upgrading to v3:** Previous versions would silently fall back to verifying only the URL `state` parameter when the cookie was missing. This fallback has been removed because it disabled CSRF protection. If you see `Auth cookie missing` errors after upgrading, ensure that `Set-Cookie` headers are propagated on redirects between your application and the user's browser.
|
|
939
|
+
|
|
911
940
|
### Troubleshooting
|
|
912
941
|
|
|
913
942
|
#### NEXT_REDIRECT error when using try/catch blocks
|
package/dist/esm/actions.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use server';
|
|
2
2
|
import { signOut, switchToOrganization } from './auth.js';
|
|
3
3
|
import { refreshSession, withAuth } from './session.js';
|
|
4
|
+
import { getAuthorizationUrl } from './get-authorization-url.js';
|
|
4
5
|
import { getWorkOS } from './workos.js';
|
|
5
6
|
/**
|
|
6
7
|
* This function is used to sanitize the auth object.
|
|
@@ -28,10 +29,28 @@ export const getOrganizationAction = async (organizationId) => {
|
|
|
28
29
|
return await getWorkOS().organizations.getOrganization(organizationId);
|
|
29
30
|
};
|
|
30
31
|
export const getAuthAction = async (options) => {
|
|
31
|
-
|
|
32
|
+
// Never pass ensureSignedIn to withAuth from a server action, because withAuth
|
|
33
|
+
// would call redirect() to an external URL, which causes CORS errors when
|
|
34
|
+
// invoked via a client-side fetch. Instead, return the sign-in URL so the
|
|
35
|
+
// client can redirect via window.location.href.
|
|
36
|
+
const auth = await withAuth();
|
|
37
|
+
const sanitized = sanitize(auth);
|
|
38
|
+
if (options?.ensureSignedIn && !auth.user) {
|
|
39
|
+
const signInUrl = await getAuthorizationUrl({ screenHint: 'sign-in' });
|
|
40
|
+
return { ...sanitized, signInUrl };
|
|
41
|
+
}
|
|
42
|
+
return sanitized;
|
|
32
43
|
};
|
|
33
44
|
export const refreshAuthAction = async ({ ensureSignedIn, organizationId, }) => {
|
|
34
|
-
|
|
45
|
+
// Never pass ensureSignedIn to refreshSession from a server action for the
|
|
46
|
+
// same CORS reason as getAuthAction above.
|
|
47
|
+
const auth = await refreshSession({ organizationId });
|
|
48
|
+
const sanitized = sanitize(auth);
|
|
49
|
+
if (ensureSignedIn && !auth.user) {
|
|
50
|
+
const signInUrl = await getAuthorizationUrl({ screenHint: 'sign-in' });
|
|
51
|
+
return { ...sanitized, signInUrl };
|
|
52
|
+
}
|
|
53
|
+
return sanitized;
|
|
35
54
|
};
|
|
36
55
|
export const switchToOrganizationAction = async (organizationId, options) => {
|
|
37
56
|
return sanitize(await switchToOrganization(organizationId, options));
|
|
@@ -47,9 +66,21 @@ export async function getAccessTokenAction() {
|
|
|
47
66
|
/**
|
|
48
67
|
* This action is used to refresh the access token from the auth object.
|
|
49
68
|
* It is used to fetch the access token from the server.
|
|
69
|
+
*
|
|
70
|
+
* Errors are caught and returned as data rather than thrown, to prevent
|
|
71
|
+
* Next.js from returning 500 responses for server action failures.
|
|
50
72
|
*/
|
|
51
73
|
export async function refreshAccessTokenAction() {
|
|
52
|
-
|
|
53
|
-
|
|
74
|
+
try {
|
|
75
|
+
const auth = await refreshSession();
|
|
76
|
+
return { accessToken: auth.accessToken };
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.warn('Failed to refresh access token:', error instanceof Error ? error.message : String(error));
|
|
80
|
+
return {
|
|
81
|
+
accessToken: undefined,
|
|
82
|
+
error: 'Failed to refresh access token',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
54
85
|
}
|
|
55
86
|
//# sourceMappingURL=actions.js.map
|
package/dist/esm/actions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/actions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/actions.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/auth.js
CHANGED
|
@@ -18,30 +18,22 @@ function revalidateTagCompat(tag) {
|
|
|
18
18
|
return fn(tag, 'max');
|
|
19
19
|
}
|
|
20
20
|
async function getAuthURLAndSetPKCECookie(options) {
|
|
21
|
-
const { url,
|
|
22
|
-
await setPKCECookie(
|
|
21
|
+
const { url, sealedState } = await getAuthorizationUrl(options);
|
|
22
|
+
await setPKCECookie(sealedState);
|
|
23
23
|
return url;
|
|
24
24
|
}
|
|
25
|
-
export async function getSignInUrl(
|
|
25
|
+
export async function getSignInUrl(authUrlOptions = {}) {
|
|
26
26
|
return getAuthURLAndSetPKCECookie({
|
|
27
|
-
|
|
27
|
+
...authUrlOptions,
|
|
28
|
+
returnPathname: authUrlOptions.returnTo,
|
|
28
29
|
screenHint: 'sign-in',
|
|
29
|
-
loginHint,
|
|
30
|
-
redirectUri,
|
|
31
|
-
prompt,
|
|
32
|
-
state,
|
|
33
|
-
returnPathname: returnTo,
|
|
34
30
|
});
|
|
35
31
|
}
|
|
36
|
-
export async function getSignUpUrl(
|
|
32
|
+
export async function getSignUpUrl(authUrlOptions = {}) {
|
|
37
33
|
return getAuthURLAndSetPKCECookie({
|
|
38
|
-
|
|
34
|
+
...authUrlOptions,
|
|
35
|
+
returnPathname: authUrlOptions.returnTo,
|
|
39
36
|
screenHint: 'sign-up',
|
|
40
|
-
loginHint,
|
|
41
|
-
redirectUri,
|
|
42
|
-
prompt,
|
|
43
|
-
state,
|
|
44
|
-
returnPathname: returnTo,
|
|
45
37
|
});
|
|
46
38
|
}
|
|
47
39
|
/**
|
|
@@ -74,7 +66,7 @@ export async function signOut({ returnTo } = {}) {
|
|
|
74
66
|
try {
|
|
75
67
|
nextCookies.delete({ name: cookieName, domain, path, sameSite, secure });
|
|
76
68
|
}
|
|
77
|
-
catch
|
|
69
|
+
catch {
|
|
78
70
|
// Some environments (e.g., vinext) only accept a string cookie name
|
|
79
71
|
nextCookies.delete(cookieName);
|
|
80
72
|
}
|
|
@@ -82,12 +74,11 @@ export async function signOut({ returnTo } = {}) {
|
|
|
82
74
|
redirect(getWorkOS().userManagement.getLogoutUrl({ sessionId, returnTo }));
|
|
83
75
|
}
|
|
84
76
|
else {
|
|
85
|
-
redirect(returnTo
|
|
77
|
+
redirect(returnTo ?? '/');
|
|
86
78
|
}
|
|
87
79
|
}
|
|
88
80
|
}
|
|
89
81
|
export async function switchToOrganization(organizationId, options = {}) {
|
|
90
|
-
var _a;
|
|
91
82
|
const { returnTo, revalidationStrategy = 'path', revalidationTags = [] } = options;
|
|
92
83
|
const headersList = await headers();
|
|
93
84
|
let result;
|
|
@@ -101,11 +92,11 @@ export async function switchToOrganization(organizationId, options = {}) {
|
|
|
101
92
|
error) {
|
|
102
93
|
const { cause } = error;
|
|
103
94
|
/* istanbul ignore next */
|
|
104
|
-
if (
|
|
95
|
+
if (cause?.rawData?.authkit_redirect_url) {
|
|
105
96
|
redirect(cause.rawData.authkit_redirect_url);
|
|
106
97
|
}
|
|
107
98
|
else {
|
|
108
|
-
if (
|
|
99
|
+
if (cause?.error === 'sso_required' || cause?.error === 'mfa_enrollment') {
|
|
109
100
|
return redirect(await getAuthURLAndSetPKCECookie({ organizationId }));
|
|
110
101
|
}
|
|
111
102
|
throw error;
|
|
@@ -123,7 +114,7 @@ export async function switchToOrganization(organizationId, options = {}) {
|
|
|
123
114
|
break;
|
|
124
115
|
}
|
|
125
116
|
}
|
|
126
|
-
catch
|
|
117
|
+
catch {
|
|
127
118
|
// revalidatePath/revalidateTag may not be available in non-Next.js environments (e.g., vinext)
|
|
128
119
|
}
|
|
129
120
|
if (revalidationStrategy !== 'none') {
|
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,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,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,KAAK,UAAU,0BAA0B,CAAC,OAA0B;IAClE,MAAM,EAAE,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getPKCECookieOptions } from './cookie.js';
|
|
2
2
|
import { WORKOS_CLIENT_ID } from './env-variables.js';
|
|
3
|
-
import { PKCE_COOKIE_NAME,
|
|
3
|
+
import { PKCE_COOKIE_NAME, getStateFromPKCECookieValue } from './pkce.js';
|
|
4
4
|
import { saveSession } from './session.js';
|
|
5
5
|
import { errorResponseWithFallback, redirectWithFallback, setCachePreventionHeaders } from './utils.js';
|
|
6
6
|
import { getWorkOS } from './workos.js';
|
|
@@ -8,40 +8,6 @@ function preventCaching(headers) {
|
|
|
8
8
|
headers.set('Vary', 'Cookie');
|
|
9
9
|
setCachePreventionHeaders(headers);
|
|
10
10
|
}
|
|
11
|
-
function handleState(state) {
|
|
12
|
-
let returnPathname = undefined;
|
|
13
|
-
let userState;
|
|
14
|
-
if (state === null || state === void 0 ? void 0 : state.includes('.')) {
|
|
15
|
-
const [internal, ...rest] = state.split('.');
|
|
16
|
-
userState = rest.join('.');
|
|
17
|
-
try {
|
|
18
|
-
// Reverse URL-safe base64 encoding
|
|
19
|
-
const decoded = internal.replace(/-/g, '+').replace(/_/g, '/');
|
|
20
|
-
returnPathname = JSON.parse(atob(decoded)).returnPathname;
|
|
21
|
-
}
|
|
22
|
-
catch (_a) {
|
|
23
|
-
// Malformed internal part, ignore it
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
else if (state) {
|
|
27
|
-
try {
|
|
28
|
-
const decoded = JSON.parse(atob(state));
|
|
29
|
-
if (decoded.returnPathname) {
|
|
30
|
-
returnPathname = decoded.returnPathname;
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
userState = state;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
catch (_b) {
|
|
37
|
-
userState = state;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return {
|
|
41
|
-
returnPathname,
|
|
42
|
-
state: userState,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
11
|
export function handleAuth(options = {}) {
|
|
46
12
|
const { returnPathname: returnPathnameOption = '/', baseURL, onSuccess, onError } = options;
|
|
47
13
|
// Throw early if baseURL is provided but invalid
|
|
@@ -54,68 +20,78 @@ export function handleAuth(options = {}) {
|
|
|
54
20
|
}
|
|
55
21
|
}
|
|
56
22
|
return async function GET(request) {
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const url = baseURL ? new URL(baseURL) : new URL(requestUrl.toString());
|
|
77
|
-
// Cleanup params
|
|
78
|
-
url.searchParams.delete('code');
|
|
79
|
-
url.searchParams.delete('state');
|
|
80
|
-
// Redirect to the requested path and store the session
|
|
81
|
-
const returnPathname = returnPathnameState !== null && returnPathnameState !== void 0 ? returnPathnameState : returnPathnameOption;
|
|
82
|
-
// Extract pathname and search params from returnPathname
|
|
83
|
-
const parsedReturnUrl = new URL(returnPathname, 'https://placeholder.com');
|
|
84
|
-
url.pathname = parsedReturnUrl.pathname;
|
|
85
|
-
url.search = parsedReturnUrl.search;
|
|
86
|
-
// Fall back to standard Response if NextResponse is not available.
|
|
87
|
-
// This is to support Next.js 13.
|
|
88
|
-
const response = redirectWithFallback(url.toString());
|
|
89
|
-
preventCaching(response.headers);
|
|
90
|
-
if (pkceCookie) {
|
|
91
|
-
response.headers.append('Set-Cookie', `${PKCE_COOKIE_NAME}=; ${getCookieOptions(request.url, true, true)}`);
|
|
92
|
-
}
|
|
93
|
-
if (!accessToken || !refreshToken)
|
|
94
|
-
throw new Error('response is missing tokens');
|
|
95
|
-
await saveSession({ accessToken, refreshToken, user, impersonator }, request);
|
|
96
|
-
if (onSuccess) {
|
|
97
|
-
await onSuccess({
|
|
98
|
-
accessToken,
|
|
99
|
-
refreshToken,
|
|
100
|
-
user,
|
|
101
|
-
impersonator,
|
|
102
|
-
oauthTokens,
|
|
103
|
-
authenticationMethod,
|
|
104
|
-
organizationId,
|
|
105
|
-
state: customState,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
return response;
|
|
23
|
+
// Always delete the PKCE cookie after handling the callback, regardless of success or error
|
|
24
|
+
// to avoid stale cookies affecting future auth attempts & prevent replays
|
|
25
|
+
const deleteCookie = `${PKCE_COOKIE_NAME}=; ${getPKCECookieOptions(request.url, true, true)}`;
|
|
26
|
+
// We want to catch any & all errors and respond the same way
|
|
27
|
+
// Firstly, by destroying the 1-use PKCE cookie to prevent replay attacks
|
|
28
|
+
// or stale cookies affecting future auth attempts
|
|
29
|
+
try {
|
|
30
|
+
// Fall back to standard URL parsing when nextUrl is not available (e.g., vinext)
|
|
31
|
+
const requestUrl = request.nextUrl ?? new URL(request.url);
|
|
32
|
+
// Gather mandatory information
|
|
33
|
+
const code = requestUrl.searchParams.get('code');
|
|
34
|
+
const state = requestUrl.searchParams.get('state');
|
|
35
|
+
const pkceCookie = request.cookies.get(PKCE_COOKIE_NAME)?.value;
|
|
36
|
+
if (!code || !state) {
|
|
37
|
+
throw new Error('Missing required auth parameter');
|
|
38
|
+
}
|
|
39
|
+
// CSRF verification: both channels (cookie + URL state) must be present and match
|
|
40
|
+
if (!pkceCookie) {
|
|
41
|
+
throw new Error('Auth cookie missing — cannot verify OAuth state. Ensure Set-Cookie headers are propagated on redirects.');
|
|
109
42
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
error: error instanceof Error ? error.message : String(error),
|
|
113
|
-
};
|
|
114
|
-
console.error(errorRes);
|
|
115
|
-
return await errorResponse(request, error);
|
|
43
|
+
if (state !== pkceCookie) {
|
|
44
|
+
throw new Error('OAuth state mismatch');
|
|
116
45
|
}
|
|
46
|
+
const { codeVerifier, customState, returnPathname: returnPathnameState, } = await getStateFromPKCECookieValue(pkceCookie);
|
|
47
|
+
// Use the code returned to us by AuthKit and authenticate the user with WorkOS
|
|
48
|
+
const { accessToken, refreshToken, user, impersonator, oauthTokens, authenticationMethod, organizationId } = await getWorkOS().userManagement.authenticateWithCode({
|
|
49
|
+
clientId: WORKOS_CLIENT_ID,
|
|
50
|
+
code,
|
|
51
|
+
codeVerifier,
|
|
52
|
+
});
|
|
53
|
+
if (!accessToken || !refreshToken) {
|
|
54
|
+
throw new Error('response is missing tokens');
|
|
55
|
+
}
|
|
56
|
+
// If baseURL is provided, use it instead of request.nextUrl
|
|
57
|
+
// This is useful if the app is being run in a container like docker where
|
|
58
|
+
// the hostname can be different from the one in the request
|
|
59
|
+
const url = baseURL ? new URL(baseURL) : new URL(requestUrl.toString());
|
|
60
|
+
// Cleanup params
|
|
61
|
+
url.searchParams.delete('code');
|
|
62
|
+
url.searchParams.delete('state');
|
|
63
|
+
// Redirect to the requested path and store the session
|
|
64
|
+
const returnPathname = returnPathnameState ?? returnPathnameOption;
|
|
65
|
+
// Extract pathname and search params from returnPathname
|
|
66
|
+
const parsedReturnUrl = new URL(returnPathname, 'https://placeholder.com');
|
|
67
|
+
url.pathname = parsedReturnUrl.pathname;
|
|
68
|
+
url.search = parsedReturnUrl.search;
|
|
69
|
+
// Fall back to standard Response if NextResponse is not available.
|
|
70
|
+
// This is to support Next.js 13.
|
|
71
|
+
const response = redirectWithFallback(url.toString());
|
|
72
|
+
preventCaching(response.headers);
|
|
73
|
+
response.headers.append('Set-Cookie', deleteCookie);
|
|
74
|
+
await saveSession({ accessToken, refreshToken, user, impersonator }, request);
|
|
75
|
+
if (onSuccess) {
|
|
76
|
+
await onSuccess({
|
|
77
|
+
accessToken,
|
|
78
|
+
refreshToken,
|
|
79
|
+
user,
|
|
80
|
+
impersonator,
|
|
81
|
+
oauthTokens,
|
|
82
|
+
authenticationMethod,
|
|
83
|
+
organizationId,
|
|
84
|
+
state: customState,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return response;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.error('[AuthKit callback error]', error);
|
|
91
|
+
const response = await errorResponse(request, error);
|
|
92
|
+
response.headers.append('Set-Cookie', deleteCookie);
|
|
93
|
+
return response;
|
|
117
94
|
}
|
|
118
|
-
return await errorResponse(request);
|
|
119
95
|
};
|
|
120
96
|
async function errorResponse(request, error) {
|
|
121
97
|
if (onError) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authkit-callback-route.js","sourceRoot":"","sources":["../../src/authkit-callback-route.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"authkit-callback-route.js","sourceRoot":"","sources":["../../src/authkit-callback-route.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,23 +1,37 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
|
2
|
+
import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { checkSessionAction, getAuthAction, handleSignOutAction, refreshAuthAction, switchToOrganizationAction, } from '../actions.js';
|
|
4
4
|
const AuthContext = createContext(undefined);
|
|
5
5
|
export const AuthKitProvider = ({ children, onSessionExpired, initialAuth }) => {
|
|
6
|
-
|
|
7
|
-
const [
|
|
8
|
-
const [
|
|
9
|
-
const [
|
|
10
|
-
const [
|
|
11
|
-
const [
|
|
12
|
-
const [
|
|
13
|
-
const [
|
|
14
|
-
const [
|
|
15
|
-
const [impersonator, setImpersonator] = useState(initialAuth === null || initialAuth === void 0 ? void 0 : initialAuth.impersonator);
|
|
6
|
+
const [user, setUser] = useState(initialAuth?.user ?? null);
|
|
7
|
+
const [sessionId, setSessionId] = useState(initialAuth?.sessionId);
|
|
8
|
+
const [organizationId, setOrganizationId] = useState(initialAuth?.organizationId);
|
|
9
|
+
const [role, setRole] = useState(initialAuth?.role);
|
|
10
|
+
const [roles, setRoles] = useState(initialAuth?.roles);
|
|
11
|
+
const [permissions, setPermissions] = useState(initialAuth?.permissions);
|
|
12
|
+
const [entitlements, setEntitlements] = useState(initialAuth?.entitlements);
|
|
13
|
+
const [featureFlags, setFeatureFlags] = useState(initialAuth?.featureFlags);
|
|
14
|
+
const [impersonator, setImpersonator] = useState(initialAuth?.impersonator);
|
|
16
15
|
const [loading, setLoading] = useState(!initialAuth);
|
|
16
|
+
const redirectingRef = useRef(false);
|
|
17
|
+
// Redirect client-side to avoid CORS errors that occur when redirect()
|
|
18
|
+
// is called from a server action to an external URL.
|
|
19
|
+
const handleSignInRedirect = useCallback((auth) => {
|
|
20
|
+
if ('signInUrl' in auth && auth.signInUrl) {
|
|
21
|
+
redirectingRef.current = true;
|
|
22
|
+
window.location.href = auth.signInUrl;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}, []);
|
|
17
27
|
const getAuth = useCallback(async ({ ensureSignedIn = false } = {}) => {
|
|
28
|
+
if (redirectingRef.current)
|
|
29
|
+
return;
|
|
18
30
|
setLoading(true);
|
|
19
31
|
try {
|
|
20
32
|
const auth = await getAuthAction({ ensureSignedIn });
|
|
33
|
+
if (handleSignInRedirect(auth))
|
|
34
|
+
return;
|
|
21
35
|
setUser(auth.user);
|
|
22
36
|
setSessionId(auth.sessionId);
|
|
23
37
|
setOrganizationId(auth.organizationId);
|
|
@@ -28,7 +42,7 @@ export const AuthKitProvider = ({ children, onSessionExpired, initialAuth }) =>
|
|
|
28
42
|
setFeatureFlags(auth.featureFlags);
|
|
29
43
|
setImpersonator(auth.impersonator);
|
|
30
44
|
}
|
|
31
|
-
catch
|
|
45
|
+
catch {
|
|
32
46
|
setUser(null);
|
|
33
47
|
setSessionId(undefined);
|
|
34
48
|
setOrganizationId(undefined);
|
|
@@ -55,9 +69,13 @@ export const AuthKitProvider = ({ children, onSessionExpired, initialAuth }) =>
|
|
|
55
69
|
return result;
|
|
56
70
|
}, []);
|
|
57
71
|
const refreshAuth = useCallback(async ({ ensureSignedIn = false, organizationId } = {}) => {
|
|
72
|
+
if (redirectingRef.current)
|
|
73
|
+
return;
|
|
58
74
|
try {
|
|
59
75
|
setLoading(true);
|
|
60
76
|
const auth = await refreshAuthAction({ ensureSignedIn, organizationId });
|
|
77
|
+
if (handleSignInRedirect(auth))
|
|
78
|
+
return;
|
|
61
79
|
setUser(auth.user);
|
|
62
80
|
setSessionId(auth.sessionId);
|
|
63
81
|
setOrganizationId(auth.organizationId);
|
|
@@ -149,7 +167,7 @@ export function useAuth({ ensureSignedIn = false } = {}) {
|
|
|
149
167
|
if (context && ensureSignedIn && !context.user && !context.loading) {
|
|
150
168
|
context.getAuth({ ensureSignedIn });
|
|
151
169
|
}
|
|
152
|
-
}, [ensureSignedIn, context
|
|
170
|
+
}, [ensureSignedIn, context?.user, context?.loading, context?.getAuth]);
|
|
153
171
|
if (!context) {
|
|
154
172
|
throw new Error('useAuth must be used within an AuthKitProvider');
|
|
155
173
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authkit-provider.js","sourceRoot":"","sources":["../../../src/components/authkit-provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,EAAE,EAAE,aAAa,EAAa,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"authkit-provider.js","sourceRoot":"","sources":["../../../src/components/authkit-provider.tsx"],"names":[],"mappings":"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"}
|