@workos-inc/authkit-nextjs 2.4.6 → 2.6.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/dist/esm/auth.js +18 -5
- package/dist/esm/auth.js.map +1 -1
- package/dist/esm/components/tokenStore.js +220 -0
- package/dist/esm/components/tokenStore.js.map +1 -0
- package/dist/esm/components/useAccessToken.js +85 -145
- package/dist/esm/components/useAccessToken.js.map +1 -1
- package/dist/esm/get-authorization-url.js +2 -1
- package/dist/esm/get-authorization-url.js.map +1 -1
- package/dist/esm/session.js +1 -1
- package/dist/esm/session.js.map +1 -1
- package/dist/esm/types/auth.d.ts +5 -3
- package/dist/esm/types/components/tokenStore.d.ts +35 -0
- package/dist/esm/types/components/useAccessToken.d.ts +26 -5
- package/dist/esm/types/interfaces.d.ts +1 -0
- package/dist/esm/types/session.d.ts +1 -0
- package/dist/esm/types/workos.d.ts +1 -1
- package/dist/esm/workos.js +1 -1
- package/package.json +2 -2
- package/src/auth.ts +19 -6
- package/src/components/tokenStore.ts +268 -0
- package/src/components/useAccessToken.ts +114 -167
- package/src/get-authorization-url.ts +2 -0
- package/src/interfaces.ts +1 -0
- package/src/session.ts +1 -1
- package/src/workos.ts +1 -1
package/dist/esm/auth.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
'use server';
|
|
2
|
+
import { decodeJwt } from 'jose';
|
|
2
3
|
import { revalidatePath, revalidateTag } from 'next/cache';
|
|
3
4
|
import { cookies, headers } from 'next/headers';
|
|
4
5
|
import { redirect } from 'next/navigation';
|
|
5
6
|
import { WORKOS_COOKIE_NAME } from './env-variables.js';
|
|
6
7
|
import { getCookieOptions } from './cookie.js';
|
|
7
8
|
import { getAuthorizationUrl } from './get-authorization-url.js';
|
|
8
|
-
import { refreshSession, withAuth } from './session.js';
|
|
9
|
+
import { getSessionFromCookie, refreshSession, withAuth } from './session.js';
|
|
9
10
|
import { getWorkOS } from './workos.js';
|
|
10
|
-
export async function getSignInUrl({ organizationId, loginHint, redirectUri, } = {}) {
|
|
11
|
-
return getAuthorizationUrl({ organizationId, screenHint: 'sign-in', loginHint, redirectUri });
|
|
11
|
+
export async function getSignInUrl({ organizationId, loginHint, redirectUri, prompt, } = {}) {
|
|
12
|
+
return getAuthorizationUrl({ organizationId, screenHint: 'sign-in', loginHint, redirectUri, prompt });
|
|
12
13
|
}
|
|
13
|
-
export async function getSignUpUrl({ organizationId, loginHint, redirectUri, } = {}) {
|
|
14
|
-
return getAuthorizationUrl({ organizationId, screenHint: 'sign-up', loginHint, redirectUri });
|
|
14
|
+
export async function getSignUpUrl({ organizationId, loginHint, redirectUri, prompt, } = {}) {
|
|
15
|
+
return getAuthorizationUrl({ organizationId, screenHint: 'sign-up', loginHint, redirectUri, prompt });
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* Sign out the user and delete the session cookie.
|
|
@@ -24,6 +25,18 @@ export async function signOut({ returnTo } = {}) {
|
|
|
24
25
|
const { sessionId: sid } = await withAuth();
|
|
25
26
|
sessionId = sid;
|
|
26
27
|
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
// Fall back to reading session directly from cookie when middleware isn't available
|
|
30
|
+
const session = await getSessionFromCookie();
|
|
31
|
+
if (session && session.accessToken) {
|
|
32
|
+
const { sid } = decodeJwt(session.accessToken);
|
|
33
|
+
sessionId = sid;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// can't recover - throw the original error.
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
27
40
|
finally {
|
|
28
41
|
const nextCookies = await cookies();
|
|
29
42
|
const cookieName = WORKOS_COOKIE_NAME || 'wos-session';
|
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,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,cAAc,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { getAccessTokenAction, refreshAccessTokenAction } from '../actions.js';
|
|
2
|
+
import { decodeJwt } from '../jwt.js';
|
|
3
|
+
const TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
4
|
+
const MIN_REFRESH_DELAY_SECONDS = 15;
|
|
5
|
+
const MAX_REFRESH_DELAY_SECONDS = 24 * 60 * 60;
|
|
6
|
+
const RETRY_DELAY_SECONDS = 300; // 5 minutes for retry on error
|
|
7
|
+
class TokenStore {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.state = {
|
|
10
|
+
token: undefined,
|
|
11
|
+
loading: false,
|
|
12
|
+
error: null,
|
|
13
|
+
};
|
|
14
|
+
this.listeners = new Set();
|
|
15
|
+
this.refreshPromise = null;
|
|
16
|
+
this.subscribe = (listener) => {
|
|
17
|
+
this.listeners.add(listener);
|
|
18
|
+
return () => {
|
|
19
|
+
this.listeners.delete(listener);
|
|
20
|
+
if (this.listeners.size === 0 && this.refreshTimeout) {
|
|
21
|
+
clearTimeout(this.refreshTimeout);
|
|
22
|
+
this.refreshTimeout = undefined;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
this.getSnapshot = () => this.state;
|
|
27
|
+
this.getServerSnapshot = () => TokenStore.SERVER_SNAPSHOT;
|
|
28
|
+
}
|
|
29
|
+
notify() {
|
|
30
|
+
this.listeners.forEach((listener) => listener());
|
|
31
|
+
}
|
|
32
|
+
setState(updates) {
|
|
33
|
+
this.state = { ...this.state, ...updates };
|
|
34
|
+
this.notify();
|
|
35
|
+
}
|
|
36
|
+
scheduleRefresh(timeUntilExpiry) {
|
|
37
|
+
if (this.refreshTimeout) {
|
|
38
|
+
clearTimeout(this.refreshTimeout);
|
|
39
|
+
this.refreshTimeout = undefined;
|
|
40
|
+
}
|
|
41
|
+
const delay = typeof timeUntilExpiry === 'undefined' ? RETRY_DELAY_SECONDS * 1000 : this.getRefreshDelay(timeUntilExpiry);
|
|
42
|
+
this.refreshTimeout = setTimeout(() => {
|
|
43
|
+
/* istanbul ignore next */
|
|
44
|
+
void this.getAccessTokenSilently().catch(() => { });
|
|
45
|
+
}, delay);
|
|
46
|
+
}
|
|
47
|
+
getRefreshDelay(timeUntilExpiry) {
|
|
48
|
+
if (timeUntilExpiry <= TOKEN_EXPIRY_BUFFER_SECONDS) {
|
|
49
|
+
return 0; // Immediate refresh
|
|
50
|
+
}
|
|
51
|
+
const idealDelay = (timeUntilExpiry - TOKEN_EXPIRY_BUFFER_SECONDS) * 1000;
|
|
52
|
+
return Math.min(Math.max(idealDelay, MIN_REFRESH_DELAY_SECONDS * 1000), MAX_REFRESH_DELAY_SECONDS * 1000);
|
|
53
|
+
}
|
|
54
|
+
parseToken(token) {
|
|
55
|
+
if (!token)
|
|
56
|
+
return null;
|
|
57
|
+
try {
|
|
58
|
+
const { payload } = decodeJwt(token);
|
|
59
|
+
const now = Math.floor(Date.now() / 1000);
|
|
60
|
+
if (typeof payload.exp !== 'number') {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const timeUntilExpiry = payload.exp - now;
|
|
64
|
+
// For short-lived tokens (< 5 minutes), use a 30-second buffer
|
|
65
|
+
// This prevents constant refreshing when tokens only last 60 seconds
|
|
66
|
+
let bufferSeconds = TOKEN_EXPIRY_BUFFER_SECONDS;
|
|
67
|
+
const totalTokenLifetime = payload.exp - (payload.iat || now);
|
|
68
|
+
if (totalTokenLifetime <= 300) {
|
|
69
|
+
// Token lifetime is 5 minutes or less - use 30 second buffer
|
|
70
|
+
bufferSeconds = 30;
|
|
71
|
+
}
|
|
72
|
+
const isExpiring = payload.exp < now + bufferSeconds;
|
|
73
|
+
return {
|
|
74
|
+
payload,
|
|
75
|
+
expiresAt: payload.exp,
|
|
76
|
+
isExpiring,
|
|
77
|
+
timeUntilExpiry,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (_a) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
isRefreshing() {
|
|
85
|
+
return this.refreshPromise !== null;
|
|
86
|
+
}
|
|
87
|
+
clearToken() {
|
|
88
|
+
this.setState({ token: undefined, error: null, loading: false });
|
|
89
|
+
if (this.refreshTimeout) {
|
|
90
|
+
clearTimeout(this.refreshTimeout);
|
|
91
|
+
this.refreshTimeout = undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async getAccessToken() {
|
|
95
|
+
const tokenData = this.parseToken(this.state.token);
|
|
96
|
+
// If we have a valid JWT that's not expiring, return it
|
|
97
|
+
if (tokenData && !tokenData.isExpiring) {
|
|
98
|
+
return this.state.token;
|
|
99
|
+
}
|
|
100
|
+
// If we have an opaque token (can't parse as JWT), return it as-is
|
|
101
|
+
if (this.state.token && !tokenData) {
|
|
102
|
+
return this.state.token;
|
|
103
|
+
}
|
|
104
|
+
// Otherwise refresh (no token or expiring JWT)
|
|
105
|
+
return this.refreshTokenSilently();
|
|
106
|
+
}
|
|
107
|
+
async getAccessTokenSilently() {
|
|
108
|
+
const tokenData = this.parseToken(this.state.token);
|
|
109
|
+
// If we have a valid JWT that's not expiring, return it
|
|
110
|
+
if (tokenData && !tokenData.isExpiring) {
|
|
111
|
+
// Valid non-expiring JWT - return cached token without server call
|
|
112
|
+
return this.state.token;
|
|
113
|
+
}
|
|
114
|
+
// If we have an opaque token (can't parse as JWT), return it as-is
|
|
115
|
+
if (this.state.token && !tokenData) {
|
|
116
|
+
// Opaque token - return cached token without server call
|
|
117
|
+
return this.state.token;
|
|
118
|
+
}
|
|
119
|
+
// Otherwise refresh (no token or expiring JWT)
|
|
120
|
+
return this.refreshTokenSilently();
|
|
121
|
+
}
|
|
122
|
+
async refreshToken() {
|
|
123
|
+
return this._refreshToken(false);
|
|
124
|
+
}
|
|
125
|
+
async refreshTokenSilently() {
|
|
126
|
+
return this._refreshToken(true);
|
|
127
|
+
}
|
|
128
|
+
async _refreshToken(silent) {
|
|
129
|
+
if (this.refreshPromise) {
|
|
130
|
+
return this.refreshPromise;
|
|
131
|
+
}
|
|
132
|
+
const previousToken = this.state.token;
|
|
133
|
+
// Only set loading for user-initiated refreshes, not background refreshes
|
|
134
|
+
if (!silent) {
|
|
135
|
+
this.setState({ loading: true, error: null });
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Clear error for silent refreshes but don't set loading
|
|
139
|
+
this.setState({ error: null });
|
|
140
|
+
}
|
|
141
|
+
this.refreshPromise = (async () => {
|
|
142
|
+
try {
|
|
143
|
+
// For manual refresh, always call refreshAccessTokenAction
|
|
144
|
+
// For silent refresh, try to get existing first, then refresh if needed
|
|
145
|
+
let token;
|
|
146
|
+
if (!silent) {
|
|
147
|
+
// Manual refresh - always force refresh
|
|
148
|
+
token = await refreshAccessTokenAction();
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Silent refresh - only fetch from server if we don't have a local token
|
|
152
|
+
if (!previousToken) {
|
|
153
|
+
// No local token, need to check server
|
|
154
|
+
token = await getAccessTokenAction();
|
|
155
|
+
const tokenData = this.parseToken(token);
|
|
156
|
+
// Set the token even if it's expiring, to preserve it in case refresh fails
|
|
157
|
+
if (token && token !== previousToken) {
|
|
158
|
+
this.setState({
|
|
159
|
+
token,
|
|
160
|
+
loading: false,
|
|
161
|
+
error: null,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// If the token from server is expiring, refresh it
|
|
165
|
+
if (!token || (tokenData && tokenData.isExpiring)) {
|
|
166
|
+
const refreshedToken = await refreshAccessTokenAction();
|
|
167
|
+
if (refreshedToken) {
|
|
168
|
+
token = refreshedToken;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// We have a local token that needs refreshing (already checked by getAccessTokenSilently)
|
|
174
|
+
token = await refreshAccessTokenAction();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Only update state if token actually changed or if loading was true
|
|
178
|
+
if (token !== previousToken || !silent) {
|
|
179
|
+
this.setState({
|
|
180
|
+
token,
|
|
181
|
+
loading: false,
|
|
182
|
+
error: null,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const tokenData = this.parseToken(token);
|
|
186
|
+
if (tokenData) {
|
|
187
|
+
this.scheduleRefresh(tokenData.timeUntilExpiry);
|
|
188
|
+
}
|
|
189
|
+
// If token is opaque (not a JWT), we don't schedule automatic refreshes
|
|
190
|
+
return token;
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
// Don't clear the token immediately - keep the stale one while retrying
|
|
194
|
+
this.setState({
|
|
195
|
+
loading: false,
|
|
196
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
197
|
+
});
|
|
198
|
+
// Schedule a retry after delay
|
|
199
|
+
this.scheduleRefresh();
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
this.refreshPromise = null;
|
|
204
|
+
}
|
|
205
|
+
})();
|
|
206
|
+
return this.refreshPromise;
|
|
207
|
+
}
|
|
208
|
+
reset() {
|
|
209
|
+
this.state = { token: undefined, loading: false, error: null };
|
|
210
|
+
this.refreshPromise = null;
|
|
211
|
+
if (this.refreshTimeout) {
|
|
212
|
+
clearTimeout(this.refreshTimeout);
|
|
213
|
+
this.refreshTimeout = undefined;
|
|
214
|
+
}
|
|
215
|
+
this.listeners.clear();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
TokenStore.SERVER_SNAPSHOT = { token: undefined, loading: false, error: null };
|
|
219
|
+
export const tokenStore = new TokenStore();
|
|
220
|
+
//# sourceMappingURL=tokenStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenStore.js","sourceRoot":"","sources":["../../../src/components/tokenStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,166 +1,106 @@
|
|
|
1
|
-
import { useCallback, useEffect,
|
|
2
|
-
import { getAccessTokenAction, refreshAccessTokenAction } from '../actions.js';
|
|
1
|
+
import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
2
|
import { useAuth } from './authkit-provider.js';
|
|
4
|
-
import {
|
|
5
|
-
const TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
6
|
-
const MIN_REFRESH_DELAY_SECONDS = 15; // minimum delay before refreshing token
|
|
7
|
-
const MAX_REFRESH_DELAY_SECONDS = 24 * 60 * 60; // 24 hours
|
|
8
|
-
const RETRY_DELAY_SECONDS = 300; // 5 minutes
|
|
9
|
-
function tokenReducer(state, action) {
|
|
10
|
-
switch (action.type) {
|
|
11
|
-
case 'FETCH_START':
|
|
12
|
-
return { ...state, loading: true, error: null };
|
|
13
|
-
case 'FETCH_SUCCESS':
|
|
14
|
-
return { ...state, loading: false, token: action.token, error: null };
|
|
15
|
-
case 'FETCH_ERROR':
|
|
16
|
-
return { ...state, loading: false, error: action.error };
|
|
17
|
-
case 'RESET':
|
|
18
|
-
return { ...state, token: undefined, loading: false, error: null };
|
|
19
|
-
// istanbul ignore next
|
|
20
|
-
default:
|
|
21
|
-
return state;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function getRefreshDelay(timeUntilExpiry) {
|
|
25
|
-
const idealDelay = (timeUntilExpiry - TOKEN_EXPIRY_BUFFER_SECONDS) * 1000;
|
|
26
|
-
return Math.min(Math.max(idealDelay, MIN_REFRESH_DELAY_SECONDS * 1000), MAX_REFRESH_DELAY_SECONDS * 1000);
|
|
27
|
-
}
|
|
28
|
-
function parseTokenPayload(token) {
|
|
29
|
-
// istanbul ignore next
|
|
30
|
-
if (!token) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
try {
|
|
34
|
-
const { payload } = decodeJwt(token);
|
|
35
|
-
const now = Math.floor(Date.now() / 1000);
|
|
36
|
-
// istanbul ignore next - if the token does not have an exp claim, we cannot determine expiry
|
|
37
|
-
if (typeof payload.exp !== 'number') {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
return {
|
|
41
|
-
payload,
|
|
42
|
-
expiresAt: payload.exp,
|
|
43
|
-
isExpiring: payload.exp < now + TOKEN_EXPIRY_BUFFER_SECONDS,
|
|
44
|
-
timeUntilExpiry: payload.exp - now,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
catch (_a) {
|
|
48
|
-
// istanbul ignore next
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
3
|
+
import { tokenStore } from './tokenStore.js';
|
|
52
4
|
/**
|
|
53
5
|
* A hook that manages access tokens with automatic refresh.
|
|
54
6
|
*/
|
|
55
7
|
export function useAccessToken() {
|
|
56
|
-
const { user, sessionId
|
|
8
|
+
const { user, sessionId } = useAuth();
|
|
57
9
|
const userId = user === null || user === void 0 ? void 0 : user.id;
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
10
|
+
const userRef = useRef(user);
|
|
11
|
+
userRef.current = user;
|
|
12
|
+
const prevSessionRef = useRef(sessionId);
|
|
13
|
+
const prevUserIdRef = useRef(userId);
|
|
14
|
+
const tokenState = useSyncExternalStore(tokenStore.subscribe, tokenStore.getSnapshot, tokenStore.getServerSnapshot);
|
|
15
|
+
// Track if we're waiting for the initial token fetch for the current user
|
|
16
|
+
// Initialize synchronously to prevent first-paint flash
|
|
17
|
+
const [isInitialTokenLoading, setIsInitialTokenLoading] = useState(() => {
|
|
18
|
+
// Only show loading if we have a user but no token yet
|
|
19
|
+
return Boolean(user && !tokenState.token && !tokenState.error);
|
|
62
20
|
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
clearTimeout(refreshTimeoutRef.current);
|
|
68
|
-
refreshTimeoutRef.current = undefined;
|
|
69
|
-
}
|
|
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]);
|
|
85
|
-
const updateToken = useCallback(async () => {
|
|
86
|
-
// istanbul ignore next - safety guard against concurrent fetches
|
|
87
|
-
if (fetchingRef.current) {
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!user) {
|
|
23
|
+
tokenStore.clearToken();
|
|
24
|
+
setIsInitialTokenLoading(false);
|
|
88
25
|
return;
|
|
89
26
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (!tokenData || tokenData.isExpiring) {
|
|
96
|
-
token = await refreshAccessTokenAction();
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// Only update state if token has changed
|
|
100
|
-
if (token !== currentTokenRef.current) {
|
|
101
|
-
dispatch({ type: 'FETCH_SUCCESS', token });
|
|
102
|
-
}
|
|
103
|
-
if (token) {
|
|
104
|
-
const tokenData = parseTokenPayload(token);
|
|
105
|
-
if (tokenData) {
|
|
106
|
-
const delay = getRefreshDelay(tokenData.timeUntilExpiry);
|
|
107
|
-
scheduleNextRefresh(delay);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return token;
|
|
111
|
-
}
|
|
112
|
-
catch (error) {
|
|
113
|
-
dispatch({ type: 'FETCH_ERROR', error: error instanceof Error ? error : new Error(String(error)) });
|
|
114
|
-
scheduleNextRefresh(RETRY_DELAY_SECONDS * 1000);
|
|
27
|
+
// Only clear token if user or session actually changed (not on initial mount)
|
|
28
|
+
const sessionChanged = prevSessionRef.current !== undefined && prevSessionRef.current !== sessionId;
|
|
29
|
+
const userChanged = prevUserIdRef.current !== undefined && prevUserIdRef.current !== userId;
|
|
30
|
+
if (sessionChanged || userChanged) {
|
|
31
|
+
tokenStore.clearToken();
|
|
115
32
|
}
|
|
116
|
-
|
|
117
|
-
|
|
33
|
+
prevSessionRef.current = sessionId;
|
|
34
|
+
prevUserIdRef.current = userId;
|
|
35
|
+
// Check if getAccessTokenSilently will actually fetch (not just return cached)
|
|
36
|
+
const currentToken = tokenStore.getSnapshot().token;
|
|
37
|
+
const tokenData = currentToken ? tokenStore.parseToken(currentToken) : null;
|
|
38
|
+
const willActuallyFetch = !currentToken || (tokenData && tokenData.isExpiring);
|
|
39
|
+
// Only show loading if we're actually going to fetch
|
|
40
|
+
if (willActuallyFetch) {
|
|
41
|
+
setIsInitialTokenLoading(true);
|
|
118
42
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
43
|
+
/* istanbul ignore next */
|
|
44
|
+
tokenStore
|
|
45
|
+
.getAccessTokenSilently()
|
|
46
|
+
.catch(() => {
|
|
47
|
+
// Error is handled in the store
|
|
48
|
+
})
|
|
49
|
+
.finally(() => {
|
|
50
|
+
// Only clear loading if we were actually loading
|
|
51
|
+
if (willActuallyFetch) {
|
|
52
|
+
setIsInitialTokenLoading(false);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}, [userId, sessionId]);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!user || typeof document === 'undefined') {
|
|
124
58
|
return;
|
|
125
59
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
scheduleNextRefresh(delay);
|
|
137
|
-
}
|
|
60
|
+
/* istanbul ignore next */
|
|
61
|
+
const refreshIfNeeded = () => {
|
|
62
|
+
tokenStore.getAccessTokenSilently().catch(() => {
|
|
63
|
+
// Error is handled in the store
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
/* istanbul ignore next */
|
|
67
|
+
const handleWake = (event) => {
|
|
68
|
+
if (event.type !== 'visibilitychange' || document.visibilityState === 'visible') {
|
|
69
|
+
refreshIfNeeded();
|
|
138
70
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
71
|
+
};
|
|
72
|
+
document.addEventListener('visibilitychange', handleWake);
|
|
73
|
+
window.addEventListener('focus', handleWake);
|
|
74
|
+
window.addEventListener('online', handleWake);
|
|
75
|
+
window.addEventListener('pageshow', handleWake);
|
|
76
|
+
return () => {
|
|
77
|
+
document.removeEventListener('visibilitychange', handleWake);
|
|
78
|
+
window.removeEventListener('focus', handleWake);
|
|
79
|
+
window.removeEventListener('online', handleWake);
|
|
80
|
+
window.removeEventListener('pageshow', handleWake);
|
|
81
|
+
};
|
|
82
|
+
}, [userId, sessionId]);
|
|
83
|
+
const getAccessToken = useCallback(async () => {
|
|
84
|
+
if (!userRef.current) {
|
|
85
|
+
return undefined;
|
|
148
86
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return;
|
|
87
|
+
return tokenStore.getAccessToken();
|
|
88
|
+
}, []);
|
|
89
|
+
// Stable refresh function
|
|
90
|
+
const refresh = useCallback(async () => {
|
|
91
|
+
if (!userRef.current) {
|
|
92
|
+
return undefined;
|
|
155
93
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
94
|
+
return tokenStore.refreshToken();
|
|
95
|
+
}, []);
|
|
96
|
+
// Combine loading states: initial token fetch OR token store is loading
|
|
97
|
+
const isLoading = isInitialTokenLoading || tokenState.loading;
|
|
159
98
|
return {
|
|
160
|
-
accessToken:
|
|
161
|
-
loading:
|
|
162
|
-
error:
|
|
99
|
+
accessToken: tokenState.token,
|
|
100
|
+
loading: isLoading,
|
|
101
|
+
error: tokenState.error,
|
|
163
102
|
refresh,
|
|
103
|
+
getAccessToken,
|
|
164
104
|
};
|
|
165
105
|
}
|
|
166
106
|
//# sourceMappingURL=useAccessToken.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAccessToken.js","sourceRoot":"","sources":["../../../src/components/useAccessToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"useAccessToken.js","sourceRoot":"","sources":["../../../src/components/useAccessToken.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { WORKOS_CLIENT_ID, WORKOS_REDIRECT_URI } from './env-variables.js';
|
|
|
3
3
|
import { headers } from 'next/headers';
|
|
4
4
|
async function getAuthorizationUrl(options = {}) {
|
|
5
5
|
const headersList = await headers();
|
|
6
|
-
const { returnPathname, screenHint, organizationId, redirectUri = headersList.get('x-redirect-uri'), loginHint, } = options;
|
|
6
|
+
const { returnPathname, screenHint, organizationId, redirectUri = headersList.get('x-redirect-uri'), loginHint, prompt, } = options;
|
|
7
7
|
return getWorkOS().userManagement.getAuthorizationUrl({
|
|
8
8
|
provider: 'authkit',
|
|
9
9
|
clientId: WORKOS_CLIENT_ID,
|
|
@@ -12,6 +12,7 @@ async function getAuthorizationUrl(options = {}) {
|
|
|
12
12
|
screenHint,
|
|
13
13
|
organizationId,
|
|
14
14
|
loginHint,
|
|
15
|
+
prompt,
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
18
|
export { getAuthorizationUrl };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-authorization-url.js","sourceRoot":"","sources":["../../src/get-authorization-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,KAAK,UAAU,mBAAmB,CAAC,UAA6B,EAAE;IAChE,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;IACpC,MAAM,EACJ,cAAc,EACd,UAAU,EACV,cAAc,EACd,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAC/C,SAAS,
|
|
1
|
+
{"version":3,"file":"get-authorization-url.js","sourceRoot":"","sources":["../../src/get-authorization-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,KAAK,UAAU,mBAAmB,CAAC,UAA6B,EAAE;IAChE,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;IACpC,MAAM,EACJ,cAAc,EACd,UAAU,EACV,cAAc,EACd,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAC/C,SAAS,EACT,MAAM,GACP,GAAG,OAAO,CAAC;IAEZ,OAAO,SAAS,EAAE,CAAC,cAAc,CAAC,mBAAmB,CAAC;QACpD,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,gBAAgB;QAC1B,WAAW,EAAE,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,mBAAmB;QAC/C,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QAC5E,UAAU;QACV,cAAc;QACd,SAAS;QACT,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
package/dist/esm/session.js
CHANGED
|
@@ -285,7 +285,7 @@ async function verifyAccessToken(accessToken) {
|
|
|
285
285
|
return false;
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
-
async function getSessionFromCookie(request) {
|
|
288
|
+
export async function getSessionFromCookie(request) {
|
|
289
289
|
const cookieName = WORKOS_COOKIE_NAME || 'wos-session';
|
|
290
290
|
let cookie;
|
|
291
291
|
if (request) {
|