@workos-inc/authkit-nextjs 2.4.3 → 2.4.5
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 -2
- package/dist/esm/auth.js +7 -6
- package/dist/esm/auth.js.map +1 -1
- package/dist/esm/components/useAccessToken.js +28 -14
- package/dist/esm/components/useAccessToken.js.map +1 -1
- package/dist/esm/cookie.js +53 -16
- package/dist/esm/cookie.js.map +1 -1
- package/dist/esm/types/workos.d.ts +1 -1
- package/dist/esm/workos.js +1 -1
- package/package.json +1 -1
- package/src/auth.ts +7 -6
- package/src/components/useAccessToken.ts +36 -14
- package/src/cookie.ts +53 -18
- package/src/workos.ts +1 -1
package/README.md
CHANGED
|
@@ -102,12 +102,20 @@ export const GET = handleAuth({
|
|
|
102
102
|
});
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
When running in environments like Docker, set the `baseURL` explicitly to ensure the redirects point to the correct location.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
export const GET = handleAuth({
|
|
109
|
+
baseURL: 'http://localhost:3000',
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
105
113
|
`handleAuth` can be used with the following options.
|
|
106
114
|
|
|
107
115
|
| Option | Default | Description |
|
|
108
116
|
| ---------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
109
117
|
| `returnPathname` | `/` | The pathname to redirect the user to after signing in |
|
|
110
|
-
| `baseURL` | `undefined` | The base URL to use for the redirect URI instead of the one in the request.
|
|
118
|
+
| `baseURL` | `undefined` | The base URL to use for the redirect URI instead of the one in the request. **Required** if the app is being run in a container like docker where the hostname can be different from the one in the request |
|
|
111
119
|
| `onSuccess` | `undefined` | A function that receives successful authentication data and can be used for side-effects like persisting tokens |
|
|
112
120
|
| `onError` | `undefined` | A function that can receive the error and the request and handle the error in its own way. |
|
|
113
121
|
|
|
@@ -429,7 +437,7 @@ If you don't want to use `authkitMiddleware` and instead want to compose your ow
|
|
|
429
437
|
export default async function middleware(request: NextRequest) {
|
|
430
438
|
// Perform logic before or after AuthKit
|
|
431
439
|
|
|
432
|
-
// Auth object contains the session, response headers and an
|
|
440
|
+
// Auth object contains the session, response headers and an authorization URL in the case that the session isn't valid
|
|
433
441
|
// This method will automatically handle setting the cookie and refreshing the session
|
|
434
442
|
const { session, headers, authorizationUrl } = await authkit(request, {
|
|
435
443
|
debug: true,
|
package/dist/esm/auth.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use server';
|
|
2
|
-
import { revalidatePath, revalidateTag } from 'next/cache';
|
|
3
|
-
import { cookies, headers } from 'next/headers';
|
|
4
|
-
import { redirect } from 'next/navigation';
|
|
5
|
-
import {
|
|
2
|
+
import { revalidatePath, revalidateTag } from 'next/cache.js';
|
|
3
|
+
import { cookies, headers } from 'next/headers.js';
|
|
4
|
+
import { redirect } from 'next/navigation.js';
|
|
5
|
+
import { WORKOS_COOKIE_NAME } from './env-variables.js';
|
|
6
|
+
import { getCookieOptions } from './cookie.js';
|
|
6
7
|
import { getAuthorizationUrl } from './get-authorization-url.js';
|
|
7
8
|
import { refreshSession, withAuth } from './session.js';
|
|
8
9
|
import { getWorkOS } from './workos.js';
|
|
@@ -26,8 +27,8 @@ export async function signOut({ returnTo } = {}) {
|
|
|
26
27
|
finally {
|
|
27
28
|
const nextCookies = await cookies();
|
|
28
29
|
const cookieName = WORKOS_COOKIE_NAME || 'wos-session';
|
|
29
|
-
const domain
|
|
30
|
-
nextCookies.delete({ name: cookieName, domain, path
|
|
30
|
+
const { domain, path, sameSite, secure } = getCookieOptions();
|
|
31
|
+
nextCookies.delete({ name: cookieName, domain, path, sameSite, secure });
|
|
31
32
|
if (sessionId) {
|
|
32
33
|
redirect(getWorkOS().userManagement.getLogoutUrl({ sessionId, returnTo }));
|
|
33
34
|
}
|
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,cAAc,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ function tokenReducer(state, action) {
|
|
|
11
11
|
case 'FETCH_START':
|
|
12
12
|
return { ...state, loading: true, error: null };
|
|
13
13
|
case 'FETCH_SUCCESS':
|
|
14
|
-
return { ...state, loading: false, token: action.token };
|
|
14
|
+
return { ...state, loading: false, token: action.token, error: null };
|
|
15
15
|
case 'FETCH_ERROR':
|
|
16
16
|
return { ...state, loading: false, error: action.error };
|
|
17
17
|
case 'RESET':
|
|
@@ -68,13 +68,26 @@ export function useAccessToken() {
|
|
|
68
68
|
refreshTimeoutRef.current = undefined;
|
|
69
69
|
}
|
|
70
70
|
}, []);
|
|
71
|
+
// Store the current token in a ref to avoid stale closures
|
|
72
|
+
const currentTokenRef = useRef(state.token);
|
|
73
|
+
currentTokenRef.current = state.token;
|
|
74
|
+
// Store updateToken in a ref to break circular dependency
|
|
75
|
+
const updateTokenRef = useRef();
|
|
76
|
+
// Centralized timer scheduling function
|
|
77
|
+
const scheduleNextRefresh = useCallback((delay) => {
|
|
78
|
+
clearRefreshTimeout();
|
|
79
|
+
refreshTimeoutRef.current = setTimeout(() => {
|
|
80
|
+
if (updateTokenRef.current) {
|
|
81
|
+
updateTokenRef.current();
|
|
82
|
+
}
|
|
83
|
+
}, delay);
|
|
84
|
+
}, [clearRefreshTimeout]);
|
|
71
85
|
const updateToken = useCallback(async () => {
|
|
72
86
|
// istanbul ignore next - safety guard against concurrent fetches
|
|
73
87
|
if (fetchingRef.current) {
|
|
74
88
|
return;
|
|
75
89
|
}
|
|
76
90
|
fetchingRef.current = true;
|
|
77
|
-
dispatch({ type: 'FETCH_START' });
|
|
78
91
|
try {
|
|
79
92
|
let token = await getAccessTokenAction();
|
|
80
93
|
if (token) {
|
|
@@ -83,26 +96,29 @@ export function useAccessToken() {
|
|
|
83
96
|
token = await refreshAccessTokenAction();
|
|
84
97
|
}
|
|
85
98
|
}
|
|
86
|
-
|
|
99
|
+
// Only update state if token has changed
|
|
100
|
+
if (token !== currentTokenRef.current) {
|
|
101
|
+
dispatch({ type: 'FETCH_SUCCESS', token });
|
|
102
|
+
}
|
|
87
103
|
if (token) {
|
|
88
104
|
const tokenData = parseTokenPayload(token);
|
|
89
105
|
if (tokenData) {
|
|
90
106
|
const delay = getRefreshDelay(tokenData.timeUntilExpiry);
|
|
91
|
-
|
|
92
|
-
refreshTimeoutRef.current = setTimeout(updateToken, delay);
|
|
107
|
+
scheduleNextRefresh(delay);
|
|
93
108
|
}
|
|
94
109
|
}
|
|
95
110
|
return token;
|
|
96
111
|
}
|
|
97
112
|
catch (error) {
|
|
98
113
|
dispatch({ type: 'FETCH_ERROR', error: error instanceof Error ? error : new Error(String(error)) });
|
|
99
|
-
|
|
100
|
-
refreshTimeoutRef.current = setTimeout(updateToken, RETRY_DELAY_SECONDS * 1000);
|
|
114
|
+
scheduleNextRefresh(RETRY_DELAY_SECONDS * 1000);
|
|
101
115
|
}
|
|
102
116
|
finally {
|
|
103
117
|
fetchingRef.current = false;
|
|
104
118
|
}
|
|
105
|
-
}, [
|
|
119
|
+
}, [scheduleNextRefresh]);
|
|
120
|
+
// Assign updateToken to ref for use in scheduleNextRefresh
|
|
121
|
+
updateTokenRef.current = updateToken;
|
|
106
122
|
const refresh = useCallback(async () => {
|
|
107
123
|
if (fetchingRef.current) {
|
|
108
124
|
return;
|
|
@@ -117,8 +133,7 @@ export function useAccessToken() {
|
|
|
117
133
|
const tokenData = parseTokenPayload(token);
|
|
118
134
|
if (tokenData) {
|
|
119
135
|
const delay = getRefreshDelay(tokenData.timeUntilExpiry);
|
|
120
|
-
|
|
121
|
-
refreshTimeoutRef.current = setTimeout(updateToken, delay);
|
|
136
|
+
scheduleNextRefresh(delay);
|
|
122
137
|
}
|
|
123
138
|
}
|
|
124
139
|
return token;
|
|
@@ -126,13 +141,12 @@ export function useAccessToken() {
|
|
|
126
141
|
catch (error) {
|
|
127
142
|
const typedError = error instanceof Error ? error : new Error(String(error));
|
|
128
143
|
dispatch({ type: 'FETCH_ERROR', error: typedError });
|
|
129
|
-
|
|
130
|
-
refreshTimeoutRef.current = setTimeout(updateToken, RETRY_DELAY_SECONDS * 1000);
|
|
144
|
+
scheduleNextRefresh(RETRY_DELAY_SECONDS * 1000);
|
|
131
145
|
}
|
|
132
146
|
finally {
|
|
133
147
|
fetchingRef.current = false;
|
|
134
148
|
}
|
|
135
|
-
}, [refreshAuth,
|
|
149
|
+
}, [refreshAuth, scheduleNextRefresh, updateToken]);
|
|
136
150
|
useEffect(() => {
|
|
137
151
|
if (!user) {
|
|
138
152
|
dispatch({ type: 'RESET' });
|
|
@@ -141,7 +155,7 @@ export function useAccessToken() {
|
|
|
141
155
|
}
|
|
142
156
|
updateToken();
|
|
143
157
|
return clearRefreshTimeout;
|
|
144
|
-
}, [userId, sessionId,
|
|
158
|
+
}, [userId, sessionId, clearRefreshTimeout]);
|
|
145
159
|
return {
|
|
146
160
|
accessToken: state.token,
|
|
147
161
|
loading: state.loading,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAccessToken.js","sourceRoot":"","sources":["../../../src/components/useAccessToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AACvC,MAAM,yBAAyB,GAAG,EAAE,CAAC,CAAC,wCAAwC;AAC9E,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW;AAC3D,MAAM,mBAAmB,GAAG,GAAG,CAAC,CAAC,YAAY;AAc7C,SAAS,YAAY,CAAC,KAAiB,EAAE,MAAmB;IAC1D,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,aAAa;YAChB,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAClD,KAAK,eAAe;YAClB,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"useAccessToken.js","sourceRoot":"","sources":["../../../src/components/useAccessToken.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/cookie.js
CHANGED
|
@@ -5,23 +5,60 @@ function assertValidSamSite(sameSite) {
|
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
export function getCookieOptions(redirectUri, asString = false, expired = false) {
|
|
8
|
-
const url = new URL(redirectUri || WORKOS_REDIRECT_URI);
|
|
9
8
|
const sameSite = WORKOS_COOKIE_SAMESITE || 'lax';
|
|
10
9
|
assertValidSamSite(sameSite);
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
10
|
+
const urlString = redirectUri || WORKOS_REDIRECT_URI;
|
|
11
|
+
// Default to secure=true when no URL available (production default)
|
|
12
|
+
// Developers should set WORKOS_REDIRECT_URI for proper local dev
|
|
13
|
+
let secure;
|
|
14
|
+
if (sameSite.toLowerCase() === 'none') {
|
|
15
|
+
secure = true;
|
|
16
|
+
}
|
|
17
|
+
else if (urlString) {
|
|
18
|
+
try {
|
|
19
|
+
const url = new URL(urlString);
|
|
20
|
+
secure = url.protocol === 'https:';
|
|
21
|
+
}
|
|
22
|
+
catch (_a) {
|
|
23
|
+
// Invalid URL - default to secure
|
|
24
|
+
secure = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
secure = true;
|
|
29
|
+
}
|
|
30
|
+
let maxAge;
|
|
31
|
+
if (expired) {
|
|
32
|
+
maxAge = 0;
|
|
33
|
+
}
|
|
34
|
+
else if (WORKOS_COOKIE_MAX_AGE) {
|
|
35
|
+
const parsed = parseInt(WORKOS_COOKIE_MAX_AGE, 10);
|
|
36
|
+
maxAge = Number.isFinite(parsed) ? parsed : 60 * 60 * 24 * 400;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
maxAge = 60 * 60 * 24 * 400;
|
|
40
|
+
}
|
|
41
|
+
if (asString) {
|
|
42
|
+
const capitalizedSameSite = sameSite.charAt(0).toUpperCase() + sameSite.slice(1).toLowerCase();
|
|
43
|
+
const parts = ['Path=/', 'HttpOnly', `SameSite=${capitalizedSameSite}`, `Max-Age=${maxAge}`];
|
|
44
|
+
if (WORKOS_COOKIE_DOMAIN) {
|
|
45
|
+
parts.push(`Domain=${WORKOS_COOKIE_DOMAIN}`);
|
|
46
|
+
}
|
|
47
|
+
if (secure) {
|
|
48
|
+
parts.push('Secure');
|
|
49
|
+
}
|
|
50
|
+
return parts.join('; ');
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
path: '/',
|
|
54
|
+
httpOnly: true,
|
|
55
|
+
secure,
|
|
56
|
+
sameSite,
|
|
57
|
+
// Defaults to 400 days, the maximum allowed by Chrome
|
|
58
|
+
// It's fine to have a long cookie expiry date as the access/refresh tokens
|
|
59
|
+
// act as the actual time-limited aspects of the session.
|
|
60
|
+
maxAge,
|
|
61
|
+
domain: WORKOS_COOKIE_DOMAIN || '',
|
|
62
|
+
};
|
|
26
63
|
}
|
|
27
64
|
//# sourceMappingURL=cookie.js.map
|
package/dist/esm/cookie.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie.js","sourceRoot":"","sources":["../../src/cookie.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAK5B,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAeD,MAAM,UAAU,gBAAgB,CAC9B,WAA2B,EAC3B,WAAoB,KAAK,EACzB,UAAmB,KAAK;IAExB,MAAM,
|
|
1
|
+
{"version":3,"file":"cookie.js","sourceRoot":"","sources":["../../src/cookie.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAK5B,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAeD,MAAM,UAAU,gBAAgB,CAC9B,WAA2B,EAC3B,WAAoB,KAAK,EACzB,UAAmB,KAAK;IAExB,MAAM,QAAQ,GAAG,sBAAsB,IAAI,KAAK,CAAC;IACjD,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAE7B,MAAM,SAAS,GAAG,WAAW,IAAI,mBAAmB,CAAC;IACrD,oEAAoE;IACpE,iEAAiE;IACjE,IAAI,MAAe,CAAC;IACpB,IAAI,QAAQ,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QACtC,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;SAAM,IAAI,SAAS,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;YAC/B,MAAM,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;QACrC,CAAC;QAAC,WAAM,CAAC;YACP,kCAAkC;YAClC,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,MAAc,CAAC;IACnB,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,GAAG,CAAC,CAAC;IACb,CAAC;SAAM,IAAI,qBAAqB,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;IACjE,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;IAC9B,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/F,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,YAAY,mBAAmB,EAAE,EAAE,WAAW,MAAM,EAAE,CAAC,CAAC;QAC7F,IAAI,oBAAoB,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,UAAU,oBAAoB,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO;QACL,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,IAAI;QACd,MAAM;QACN,QAAQ;QACR,sDAAsD;QACtD,2EAA2E;QAC3E,yDAAyD;QACzD,MAAM;QACN,MAAM,EAAE,oBAAoB,IAAI,EAAE;KACnC,CAAC;AACJ,CAAC"}
|
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.
|
|
4
|
+
export const VERSION = '2.4.5';
|
|
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
package/src/auth.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use server';
|
|
2
2
|
|
|
3
|
-
import { revalidatePath, revalidateTag } from 'next/cache';
|
|
4
|
-
import { cookies, headers } from 'next/headers';
|
|
5
|
-
import { redirect } from 'next/navigation';
|
|
6
|
-
import {
|
|
3
|
+
import { revalidatePath, revalidateTag } from 'next/cache.js';
|
|
4
|
+
import { cookies, headers } from 'next/headers.js';
|
|
5
|
+
import { redirect } from 'next/navigation.js';
|
|
6
|
+
import { WORKOS_COOKIE_NAME } from './env-variables.js';
|
|
7
|
+
import { getCookieOptions } from './cookie.js';
|
|
7
8
|
import { getAuthorizationUrl } from './get-authorization-url.js';
|
|
8
9
|
import { SwitchToOrganizationOptions, UserInfo } from './interfaces.js';
|
|
9
10
|
import { refreshSession, withAuth } from './session.js';
|
|
@@ -38,8 +39,8 @@ export async function signOut({ returnTo }: { returnTo?: string } = {}) {
|
|
|
38
39
|
} finally {
|
|
39
40
|
const nextCookies = await cookies();
|
|
40
41
|
const cookieName = WORKOS_COOKIE_NAME || 'wos-session';
|
|
41
|
-
const domain
|
|
42
|
-
nextCookies.delete({ name: cookieName, domain, path
|
|
42
|
+
const { domain, path, sameSite, secure } = getCookieOptions();
|
|
43
|
+
nextCookies.delete({ name: cookieName, domain, path, sameSite, secure });
|
|
43
44
|
|
|
44
45
|
if (sessionId) {
|
|
45
46
|
redirect(getWorkOS().userManagement.getLogoutUrl({ sessionId, returnTo }));
|
|
@@ -25,7 +25,7 @@ function tokenReducer(state: TokenState, action: TokenAction): TokenState {
|
|
|
25
25
|
case 'FETCH_START':
|
|
26
26
|
return { ...state, loading: true, error: null };
|
|
27
27
|
case 'FETCH_SUCCESS':
|
|
28
|
-
return { ...state, loading: false, token: action.token };
|
|
28
|
+
return { ...state, loading: false, token: action.token, error: null };
|
|
29
29
|
case 'FETCH_ERROR':
|
|
30
30
|
return { ...state, loading: false, error: action.error };
|
|
31
31
|
case 'RESET':
|
|
@@ -90,6 +90,26 @@ export function useAccessToken() {
|
|
|
90
90
|
}
|
|
91
91
|
}, []);
|
|
92
92
|
|
|
93
|
+
// Store the current token in a ref to avoid stale closures
|
|
94
|
+
const currentTokenRef = useRef<string | undefined>(state.token);
|
|
95
|
+
currentTokenRef.current = state.token;
|
|
96
|
+
|
|
97
|
+
// Store updateToken in a ref to break circular dependency
|
|
98
|
+
const updateTokenRef = useRef<() => Promise<string | undefined>>();
|
|
99
|
+
|
|
100
|
+
// Centralized timer scheduling function
|
|
101
|
+
const scheduleNextRefresh = useCallback(
|
|
102
|
+
(delay: number) => {
|
|
103
|
+
clearRefreshTimeout();
|
|
104
|
+
refreshTimeoutRef.current = setTimeout(() => {
|
|
105
|
+
if (updateTokenRef.current) {
|
|
106
|
+
updateTokenRef.current();
|
|
107
|
+
}
|
|
108
|
+
}, delay);
|
|
109
|
+
},
|
|
110
|
+
[clearRefreshTimeout],
|
|
111
|
+
);
|
|
112
|
+
|
|
93
113
|
const updateToken = useCallback(async () => {
|
|
94
114
|
// istanbul ignore next - safety guard against concurrent fetches
|
|
95
115
|
if (fetchingRef.current) {
|
|
@@ -97,7 +117,7 @@ export function useAccessToken() {
|
|
|
97
117
|
}
|
|
98
118
|
|
|
99
119
|
fetchingRef.current = true;
|
|
100
|
-
|
|
120
|
+
|
|
101
121
|
try {
|
|
102
122
|
let token = await getAccessTokenAction();
|
|
103
123
|
if (token) {
|
|
@@ -107,26 +127,30 @@ export function useAccessToken() {
|
|
|
107
127
|
}
|
|
108
128
|
}
|
|
109
129
|
|
|
110
|
-
|
|
130
|
+
// Only update state if token has changed
|
|
131
|
+
if (token !== currentTokenRef.current) {
|
|
132
|
+
dispatch({ type: 'FETCH_SUCCESS', token });
|
|
133
|
+
}
|
|
111
134
|
|
|
112
135
|
if (token) {
|
|
113
136
|
const tokenData = parseTokenPayload(token);
|
|
114
137
|
if (tokenData) {
|
|
115
138
|
const delay = getRefreshDelay(tokenData.timeUntilExpiry);
|
|
116
|
-
|
|
117
|
-
refreshTimeoutRef.current = setTimeout(updateToken, delay);
|
|
139
|
+
scheduleNextRefresh(delay);
|
|
118
140
|
}
|
|
119
141
|
}
|
|
120
142
|
|
|
121
143
|
return token;
|
|
122
144
|
} catch (error) {
|
|
123
145
|
dispatch({ type: 'FETCH_ERROR', error: error instanceof Error ? error : new Error(String(error)) });
|
|
124
|
-
|
|
125
|
-
refreshTimeoutRef.current = setTimeout(updateToken, RETRY_DELAY_SECONDS * 1000);
|
|
146
|
+
scheduleNextRefresh(RETRY_DELAY_SECONDS * 1000);
|
|
126
147
|
} finally {
|
|
127
148
|
fetchingRef.current = false;
|
|
128
149
|
}
|
|
129
|
-
}, [
|
|
150
|
+
}, [scheduleNextRefresh]);
|
|
151
|
+
|
|
152
|
+
// Assign updateToken to ref for use in scheduleNextRefresh
|
|
153
|
+
updateTokenRef.current = updateToken;
|
|
130
154
|
|
|
131
155
|
const refresh = useCallback(async () => {
|
|
132
156
|
if (fetchingRef.current) {
|
|
@@ -146,8 +170,7 @@ export function useAccessToken() {
|
|
|
146
170
|
const tokenData = parseTokenPayload(token);
|
|
147
171
|
if (tokenData) {
|
|
148
172
|
const delay = getRefreshDelay(tokenData.timeUntilExpiry);
|
|
149
|
-
|
|
150
|
-
refreshTimeoutRef.current = setTimeout(updateToken, delay);
|
|
173
|
+
scheduleNextRefresh(delay);
|
|
151
174
|
}
|
|
152
175
|
}
|
|
153
176
|
|
|
@@ -155,12 +178,11 @@ export function useAccessToken() {
|
|
|
155
178
|
} catch (error) {
|
|
156
179
|
const typedError = error instanceof Error ? error : new Error(String(error));
|
|
157
180
|
dispatch({ type: 'FETCH_ERROR', error: typedError });
|
|
158
|
-
|
|
159
|
-
refreshTimeoutRef.current = setTimeout(updateToken, RETRY_DELAY_SECONDS * 1000);
|
|
181
|
+
scheduleNextRefresh(RETRY_DELAY_SECONDS * 1000);
|
|
160
182
|
} finally {
|
|
161
183
|
fetchingRef.current = false;
|
|
162
184
|
}
|
|
163
|
-
}, [refreshAuth,
|
|
185
|
+
}, [refreshAuth, scheduleNextRefresh, updateToken]);
|
|
164
186
|
|
|
165
187
|
useEffect(() => {
|
|
166
188
|
if (!user) {
|
|
@@ -171,7 +193,7 @@ export function useAccessToken() {
|
|
|
171
193
|
updateToken();
|
|
172
194
|
|
|
173
195
|
return clearRefreshTimeout;
|
|
174
|
-
}, [userId, sessionId,
|
|
196
|
+
}, [userId, sessionId, clearRefreshTimeout]);
|
|
175
197
|
|
|
176
198
|
return {
|
|
177
199
|
accessToken: state.token,
|
package/src/cookie.ts
CHANGED
|
@@ -32,24 +32,59 @@ export function getCookieOptions(
|
|
|
32
32
|
asString: boolean = false,
|
|
33
33
|
expired: boolean = false,
|
|
34
34
|
): CookieOptions | string {
|
|
35
|
-
const url = new URL(redirectUri || WORKOS_REDIRECT_URI);
|
|
36
35
|
const sameSite = WORKOS_COOKIE_SAMESITE || 'lax';
|
|
37
36
|
assertValidSamSite(sameSite);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
37
|
+
|
|
38
|
+
const urlString = redirectUri || WORKOS_REDIRECT_URI;
|
|
39
|
+
// Default to secure=true when no URL available (production default)
|
|
40
|
+
// Developers should set WORKOS_REDIRECT_URI for proper local dev
|
|
41
|
+
let secure: boolean;
|
|
42
|
+
if (sameSite.toLowerCase() === 'none') {
|
|
43
|
+
secure = true;
|
|
44
|
+
} else if (urlString) {
|
|
45
|
+
try {
|
|
46
|
+
const url = new URL(urlString);
|
|
47
|
+
secure = url.protocol === 'https:';
|
|
48
|
+
} catch {
|
|
49
|
+
// Invalid URL - default to secure
|
|
50
|
+
secure = true;
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
secure = true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let maxAge: number;
|
|
57
|
+
if (expired) {
|
|
58
|
+
maxAge = 0;
|
|
59
|
+
} else if (WORKOS_COOKIE_MAX_AGE) {
|
|
60
|
+
const parsed = parseInt(WORKOS_COOKIE_MAX_AGE, 10);
|
|
61
|
+
maxAge = Number.isFinite(parsed) ? parsed : 60 * 60 * 24 * 400;
|
|
62
|
+
} else {
|
|
63
|
+
maxAge = 60 * 60 * 24 * 400;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (asString) {
|
|
67
|
+
const capitalizedSameSite = sameSite.charAt(0).toUpperCase() + sameSite.slice(1).toLowerCase();
|
|
68
|
+
const parts = ['Path=/', 'HttpOnly', `SameSite=${capitalizedSameSite}`, `Max-Age=${maxAge}`];
|
|
69
|
+
if (WORKOS_COOKIE_DOMAIN) {
|
|
70
|
+
parts.push(`Domain=${WORKOS_COOKIE_DOMAIN}`);
|
|
71
|
+
}
|
|
72
|
+
if (secure) {
|
|
73
|
+
parts.push('Secure');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return parts.join('; ');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
path: '/',
|
|
81
|
+
httpOnly: true,
|
|
82
|
+
secure,
|
|
83
|
+
sameSite,
|
|
84
|
+
// Defaults to 400 days, the maximum allowed by Chrome
|
|
85
|
+
// It's fine to have a long cookie expiry date as the access/refresh tokens
|
|
86
|
+
// act as the actual time-limited aspects of the session.
|
|
87
|
+
maxAge,
|
|
88
|
+
domain: WORKOS_COOKIE_DOMAIN || '',
|
|
89
|
+
};
|
|
55
90
|
}
|
package/src/workos.ts
CHANGED
|
@@ -2,7 +2,7 @@ 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
4
|
|
|
5
|
-
export const VERSION = '2.4.
|
|
5
|
+
export const VERSION = '2.4.5';
|
|
6
6
|
|
|
7
7
|
const options = {
|
|
8
8
|
apiHostname: WORKOS_API_HOSTNAME,
|