@oxyhq/auth 2.0.6 → 2.0.8
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 +15 -1
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/WebOxyProvider.js +49 -8
- package/dist/cjs/hooks/useWebSSO.js +8 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/WebOxyProvider.js +49 -8
- package/dist/esm/hooks/useWebSSO.js +8 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/WebOxyProvider.tsx +49 -7
- package/src/hooks/useWebSSO.ts +8 -1
|
@@ -16,6 +16,38 @@ const core_1 = require("@oxyhq/core");
|
|
|
16
16
|
const react_query_1 = require("@tanstack/react-query");
|
|
17
17
|
const queryClient_1 = require("./hooks/queryClient");
|
|
18
18
|
const WebOxyContext = (0, react_1.createContext)(null);
|
|
19
|
+
/**
|
|
20
|
+
* Module-level run-once guard for the provider's silent sign-in step.
|
|
21
|
+
*
|
|
22
|
+
* The init effect runs again whenever the provider remounts (route change,
|
|
23
|
+
* StrictMode double-invoke, error-boundary recovery). The redirect-callback
|
|
24
|
+
* and local-session-restore steps are cheap and idempotent, but
|
|
25
|
+
* `crossDomainAuth.silentSignIn()` is NOT: it first tries FedCM silent
|
|
26
|
+
* mediation (`navigator.credentials.get`) and, if that yields nothing, falls
|
|
27
|
+
* back to an iframe-based silent auth against `/auth/silent`.
|
|
28
|
+
*
|
|
29
|
+
* The FedCM leg is now centrally memoized inside `@oxyhq/core`'s
|
|
30
|
+
* `silentSignInWithFedCM` (at-most-once `navigator.credentials.get` per page
|
|
31
|
+
* load). The iframe fallback, however, is a SEPARATE mechanism the core guard
|
|
32
|
+
* does not cover — without this guard a remount storm would create a hidden
|
|
33
|
+
* iframe per remount. So this guard is intentionally retained to keep the
|
|
34
|
+
* provider's WHOLE silent step run-once. Keyed on `origin + baseURL` to match
|
|
35
|
+
* the core guard's keying (so the two stay in lockstep) and to survive
|
|
36
|
+
* instance churn; never cleared because only a fresh page load can change the
|
|
37
|
+
* IdP/iframe session state.
|
|
38
|
+
*/
|
|
39
|
+
const silentSignInAttempted = new Set();
|
|
40
|
+
function silentSignInKey(oxyServices) {
|
|
41
|
+
const origin = typeof window !== 'undefined' ? window.location.origin : 'no-origin';
|
|
42
|
+
let baseURL = '';
|
|
43
|
+
try {
|
|
44
|
+
baseURL = oxyServices.getBaseURL();
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
baseURL = '';
|
|
48
|
+
}
|
|
49
|
+
return `${origin}|${baseURL}`;
|
|
50
|
+
}
|
|
19
51
|
/**
|
|
20
52
|
* Web-only Oxy Provider
|
|
21
53
|
*
|
|
@@ -117,15 +149,24 @@ function WebOxyProvider({ children, baseURL, authWebUrl, onAuthStateChange, onEr
|
|
|
117
149
|
await authManager.signOut();
|
|
118
150
|
}
|
|
119
151
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
152
|
+
// Silent sign-in: run AT MOST ONCE per page load. A remount (route
|
|
153
|
+
// change / StrictMode / error recovery) must not re-trigger the
|
|
154
|
+
// browser credential request OR the iframe fallback. The FedCM leg is
|
|
155
|
+
// additionally memoized in core; this guard also covers the iframe
|
|
156
|
+
// fallback that core does not.
|
|
157
|
+
const ssoKey = silentSignInKey(oxyServices);
|
|
158
|
+
if (!silentSignInAttempted.has(ssoKey)) {
|
|
159
|
+
silentSignInAttempted.add(ssoKey);
|
|
160
|
+
try {
|
|
161
|
+
const session = await crossDomainAuth.silentSignIn();
|
|
162
|
+
if (mounted && session?.user) {
|
|
163
|
+
await handleAuthSuccess(session, 'fedcm');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// Silent sign-in failed — resolve to unauthenticated below.
|
|
125
169
|
}
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
// Silent sign-in failed
|
|
129
170
|
}
|
|
130
171
|
if (mounted)
|
|
131
172
|
setIsLoading(false);
|
|
@@ -121,7 +121,14 @@ function useWebSSO({ oxyServices, onSessionFound, onSSOUnavailable, onError, ena
|
|
|
121
121
|
isCheckingRef.current = false;
|
|
122
122
|
}
|
|
123
123
|
}, [oxyServices, onSessionFound, onError, fedCMSupported]);
|
|
124
|
-
// Auto-check SSO on mount (web only, FedCM only, not on auth domain)
|
|
124
|
+
// Auto-check SSO on mount (web only, FedCM only, not on auth domain).
|
|
125
|
+
//
|
|
126
|
+
// `hasCheckedRef` is a cheap per-instance fast-path so effect re-runs (from
|
|
127
|
+
// changing deps) within one mount never re-fire. The page-load run-once
|
|
128
|
+
// guarantee — silent SSO invoking `navigator.credentials.get` AT MOST ONCE
|
|
129
|
+
// per page load across remounts / StrictMode / multiple consumers — lives in
|
|
130
|
+
// `@oxyhq/core`'s `silentSignInWithFedCM`, which memoizes the first silent
|
|
131
|
+
// attempt's result for this origin + API. The hook therefore calls it freely.
|
|
125
132
|
(0, react_1.useEffect)(() => {
|
|
126
133
|
if (!enabled || !isWebBrowser() || hasCheckedRef.current || isIdentityProvider()) {
|
|
127
134
|
if (isIdentityProvider()) {
|