@fluixi/oauth2 1.0.0-alpha.11 → 1.0.0-alpha.12
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/backchannel.cjs +462 -0
- package/dist/backchannel.d.ts +39 -0
- package/dist/backchannel.d.ts.map +1 -0
- package/dist/backchannel.js +97 -0
- package/dist/backchannel.mjs +307 -0
- package/dist/{browser-N432SMC3.mjs → browser-VTMW33ZW.mjs} +2 -2
- package/dist/browser.cjs +6 -1
- package/dist/browser.mjs +6 -1
- package/dist/callback.mjs +1 -1
- package/dist/chunk-6TQMM3FM.mjs +108 -0
- package/dist/{chunk-4TPZVJSR.mjs → chunk-MT6KXLLJ.mjs} +1 -1
- package/dist/{chunk-ZVDC3JW7.mjs → chunk-WRXP7BLV.mjs} +1 -1
- package/dist/discovery.cjs +6 -1
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +6 -1
- package/dist/discovery.mjs +6 -1
- package/dist/dpop-QIL3GC4U.mjs +22 -0
- package/dist/{dpop-DYUR2CH2.mjs → dpop-ZVQMDWG5.mjs} +4 -4
- package/dist/index.cjs +107 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.mjs +111 -11
- package/dist/server.cjs +649 -137
- package/dist/server.d.ts +64 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +376 -61
- package/dist/server.mjs +532 -139
- package/dist/service-client.cjs +7 -2
- package/dist/service-client.mjs +9 -4
- package/dist/service.cjs +104 -5
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +38 -6
- package/dist/service.mjs +105 -6
- package/dist/session-monitor.cjs +98 -0
- package/dist/session-monitor.d.ts +32 -0
- package/dist/session-monitor.d.ts.map +1 -0
- package/dist/session-monitor.js +104 -0
- package/dist/session-monitor.mjs +77 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/verify.cjs +7 -2
- package/dist/verify.mjs +12 -7
- package/package.json +15 -15
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @fluixi/oauth2 v1.0.0-alpha.
|
|
1
|
+
/*! @fluixi/oauth2 v1.0.0-alpha.12 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
2
|
"use strict";
|
|
3
3
|
var __create = Object.create;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -51,7 +51,8 @@ __export(index_exports, {
|
|
|
51
51
|
paramsFromUrl: () => paramsFromUrl,
|
|
52
52
|
proofFor: () => proofFor,
|
|
53
53
|
safeReturnTo: () => safeReturnTo,
|
|
54
|
-
thumbprintOf: () => thumbprintOf
|
|
54
|
+
thumbprintOf: () => thumbprintOf,
|
|
55
|
+
watchProviderSession: () => watchProviderSession
|
|
55
56
|
});
|
|
56
57
|
module.exports = __toCommonJS(index_exports);
|
|
57
58
|
|
|
@@ -364,8 +365,12 @@ async function discover(issuer, fetcher = fetch) {
|
|
|
364
365
|
try {
|
|
365
366
|
response = await fetcher(documentUrl(issuer));
|
|
366
367
|
} catch (cause) {
|
|
368
|
+
const why = cause instanceof Error ? cause.message : String(cause);
|
|
367
369
|
throw new OAuthError(
|
|
368
|
-
|
|
370
|
+
typeof window === "undefined" ? (
|
|
371
|
+
// On a server nothing blocks the read: the provider is down, or the address is wrong.
|
|
372
|
+
`Could not reach the provider at ${documentUrl(issuer)}: is it running, and is the issuer right? (${why})`
|
|
373
|
+
) : `Could not read the discovery document at ${documentUrl(issuer)}. In a browser this is usually the provider refusing a cross-origin read: give \`endpoints\` directly, or resolve them on a server. (${why})`,
|
|
369
374
|
"discovery_unreachable"
|
|
370
375
|
);
|
|
371
376
|
}
|
|
@@ -390,6 +395,7 @@ async function discover(issuer, fetcher = fetch) {
|
|
|
390
395
|
jwks: doc.jwks_uri,
|
|
391
396
|
introspection: doc.introspection_endpoint,
|
|
392
397
|
revocation: doc.revocation_endpoint,
|
|
398
|
+
checkSession: doc.check_session_iframe,
|
|
393
399
|
issuer: doc.issuer ?? issuer
|
|
394
400
|
};
|
|
395
401
|
})();
|
|
@@ -848,6 +854,81 @@ function createServerClient(config, fetcher = fetch) {
|
|
|
848
854
|
};
|
|
849
855
|
}
|
|
850
856
|
|
|
857
|
+
// src/session-monitor.ts
|
|
858
|
+
var SETTLE_MS = 15e3;
|
|
859
|
+
var GUARD_KEY = "fx-session-check";
|
|
860
|
+
function recentlyActed() {
|
|
861
|
+
try {
|
|
862
|
+
return Date.now() - Number(sessionStorage.getItem(GUARD_KEY) ?? 0) < SETTLE_MS;
|
|
863
|
+
} catch {
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
function markActed() {
|
|
868
|
+
try {
|
|
869
|
+
sessionStorage.setItem(GUARD_KEY, String(Date.now()));
|
|
870
|
+
} catch {
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
function watchProviderSession(options = {}) {
|
|
874
|
+
if (typeof window === "undefined" || typeof document === "undefined") return () => {
|
|
875
|
+
};
|
|
876
|
+
const base = (options.basePath ?? "/auth").replace(/\/$/, "");
|
|
877
|
+
const fetcher = options.fetcher ?? fetch;
|
|
878
|
+
const onChange = options.onChange ?? (() => {
|
|
879
|
+
const login = new URLSearchParams({ prompt: "none", returnTo: location.pathname + location.search });
|
|
880
|
+
location.assign(`${base}/login?${login}`);
|
|
881
|
+
});
|
|
882
|
+
let stopped = false;
|
|
883
|
+
const cleanups = [];
|
|
884
|
+
const stop = () => {
|
|
885
|
+
stopped = true;
|
|
886
|
+
for (const cleanup of cleanups.splice(0)) cleanup();
|
|
887
|
+
};
|
|
888
|
+
void (async () => {
|
|
889
|
+
const check = await fetcher(`${base}/session-check`, { credentials: "same-origin" }).then((response) => response.ok ? response.json() : null).catch(() => null);
|
|
890
|
+
if (stopped || !check?.frame || !check.state) return;
|
|
891
|
+
const origin = new URL(check.frame).origin;
|
|
892
|
+
const frame = document.createElement("iframe");
|
|
893
|
+
frame.src = check.frame;
|
|
894
|
+
frame.title = "session check";
|
|
895
|
+
frame.setAttribute("aria-hidden", "true");
|
|
896
|
+
frame.tabIndex = -1;
|
|
897
|
+
frame.style.cssText = "position:absolute;width:0;height:0;border:0;visibility:hidden";
|
|
898
|
+
const message = `${check.clientId} ${check.state}`;
|
|
899
|
+
const ask = () => {
|
|
900
|
+
if (!stopped && document.visibilityState === "visible") frame.contentWindow?.postMessage(message, origin);
|
|
901
|
+
};
|
|
902
|
+
let confirmed = false;
|
|
903
|
+
const answer = (event) => {
|
|
904
|
+
if (event.origin !== origin || event.source !== frame.contentWindow) return;
|
|
905
|
+
if (event.data === "unchanged") confirmed = true;
|
|
906
|
+
else if (event.data === "changed") {
|
|
907
|
+
stop();
|
|
908
|
+
if (!confirmed && recentlyActed()) return;
|
|
909
|
+
markActed();
|
|
910
|
+
onChange();
|
|
911
|
+
} else if (event.data === "error") {
|
|
912
|
+
stop();
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
window.addEventListener("message", answer);
|
|
916
|
+
frame.addEventListener("load", ask);
|
|
917
|
+
document.addEventListener("visibilitychange", ask);
|
|
918
|
+
window.addEventListener("focus", ask);
|
|
919
|
+
const timer = setInterval(ask, options.intervalMs ?? 3e3);
|
|
920
|
+
document.body.appendChild(frame);
|
|
921
|
+
cleanups.push(() => {
|
|
922
|
+
window.removeEventListener("message", answer);
|
|
923
|
+
document.removeEventListener("visibilitychange", ask);
|
|
924
|
+
window.removeEventListener("focus", ask);
|
|
925
|
+
clearInterval(timer);
|
|
926
|
+
frame.remove();
|
|
927
|
+
});
|
|
928
|
+
})();
|
|
929
|
+
return stop;
|
|
930
|
+
}
|
|
931
|
+
|
|
851
932
|
// src/service.ts
|
|
852
933
|
function paramsFromUrl(url) {
|
|
853
934
|
const href = url ?? (typeof location === "undefined" ? null : location.href);
|
|
@@ -874,16 +955,19 @@ function createAuthService(options) {
|
|
|
874
955
|
function buildAuthService(options) {
|
|
875
956
|
const client = clientFor(options);
|
|
876
957
|
let latest = null;
|
|
958
|
+
const fetchUserFor = async (token) => {
|
|
959
|
+
if (options.fetchUser) return options.fetchUser(token);
|
|
960
|
+
return client.fetchUser(token === COOKIE_SESSION ? void 0 : token);
|
|
961
|
+
};
|
|
962
|
+
const resumesFromCookie = options.config.tokens === "server" && typeof window !== "undefined";
|
|
963
|
+
const [ready, setReady] = (0, import_signal.createSignal)(!resumesFromCookie);
|
|
877
964
|
const session = (0, import_session.createSession)({
|
|
878
965
|
/** The credential is the callback, so this is the code exchange. */
|
|
879
966
|
async login(params) {
|
|
880
967
|
latest = await client.handleCallback(params);
|
|
881
968
|
return { token: latest.accessToken, expiresAt: latest.expiresAt };
|
|
882
969
|
},
|
|
883
|
-
|
|
884
|
-
if (options.fetchUser) return options.fetchUser(token);
|
|
885
|
-
return client.fetchUser(token === COOKIE_SESSION ? void 0 : token);
|
|
886
|
-
},
|
|
970
|
+
fetchUser: fetchUserFor,
|
|
887
971
|
async refresh() {
|
|
888
972
|
latest = await client.refresh();
|
|
889
973
|
return { token: latest.accessToken, expiresAt: latest.expiresAt };
|
|
@@ -906,11 +990,27 @@ function buildAuthService(options) {
|
|
|
906
990
|
});
|
|
907
991
|
const hooks = (0, import_client.createAuthHooks)({
|
|
908
992
|
session,
|
|
993
|
+
ready,
|
|
909
994
|
navigate: options.navigate,
|
|
910
995
|
loginPath: options.loginPath ?? "/login",
|
|
911
996
|
homePath: options.homePath ?? "/",
|
|
912
997
|
forbiddenPath: options.forbiddenPath ?? "/403"
|
|
913
998
|
});
|
|
999
|
+
if (resumesFromCookie && options.config.tokens === "server" && options.config.watchSession !== false) {
|
|
1000
|
+
watchProviderSession({ basePath: options.config.basePath });
|
|
1001
|
+
}
|
|
1002
|
+
const renderedSignedOut = hooks.store.seeded && hooks.store.value().user == null;
|
|
1003
|
+
if (resumesFromCookie && renderedSignedOut) setReady(true);
|
|
1004
|
+
else if (resumesFromCookie) {
|
|
1005
|
+
void (async () => {
|
|
1006
|
+
try {
|
|
1007
|
+
await session.adopt(COOKIE_SESSION, await fetchUserFor(COOKIE_SESSION));
|
|
1008
|
+
} catch {
|
|
1009
|
+
} finally {
|
|
1010
|
+
setReady(true);
|
|
1011
|
+
}
|
|
1012
|
+
})();
|
|
1013
|
+
}
|
|
914
1014
|
return Object.assign(session, {
|
|
915
1015
|
client,
|
|
916
1016
|
protectedRoute: hooks.protectedRoute,
|
package/dist/index.d.ts
CHANGED
|
@@ -93,6 +93,8 @@ export type { AuthService, AuthServiceOptions, AuthCredentials } from './service
|
|
|
93
93
|
export { createBrowserClient } from './browser.js';
|
|
94
94
|
export { createServerClient, COOKIE_SESSION } from './server-client.js';
|
|
95
95
|
export { discover, clearDiscoveryCache } from './discovery.js';
|
|
96
|
+
export { watchProviderSession } from './session-monitor.js';
|
|
97
|
+
export type { SessionCheck, WatchOptions } from './session-monitor.js';
|
|
96
98
|
export { createPkcePair, createVerifier, createChallenge, createStateValue, expiryFromJwt, } from './pkce.js';
|
|
97
99
|
export { createDpopKey, proofFor, thumbprintOf, boundKeyOf } from './dpop.js';
|
|
98
100
|
export type { DpopKey, ProofOptions } from './dpop.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AACH,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC9E,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,YAAY,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACd,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,MAAM,GACP,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AACH,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC9E,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,YAAY,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACd,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,MAAM,GACP,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -92,6 +92,7 @@ export { createAuthService, paramsFromUrl } from './service.js';
|
|
|
92
92
|
export { createBrowserClient } from './browser.js';
|
|
93
93
|
export { createServerClient, COOKIE_SESSION } from './server-client.js';
|
|
94
94
|
export { discover, clearDiscoveryCache } from './discovery.js';
|
|
95
|
+
export { watchProviderSession } from './session-monitor.js';
|
|
95
96
|
export { createPkcePair, createVerifier, createChallenge, createStateValue, expiryFromJwt, } from './pkce.js';
|
|
96
97
|
export { createDpopKey, proofFor, thumbprintOf, boundKeyOf } from './dpop.js';
|
|
97
98
|
export { safeReturnTo } from './return-to.js';
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/*! @fluixi/oauth2 v1.0.0-alpha.
|
|
2
|
-
import "./chunk-
|
|
1
|
+
/*! @fluixi/oauth2 v1.0.0-alpha.12 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
|
+
import "./chunk-MT6KXLLJ.mjs";
|
|
3
3
|
|
|
4
4
|
// src/service.ts
|
|
5
|
-
import { markReactiveScope, openReactiveScope, withReactiveScope } from "@fluixi/reactive/signal";
|
|
5
|
+
import { createSignal, markReactiveScope, openReactiveScope, withReactiveScope } from "@fluixi/reactive/signal";
|
|
6
6
|
import { createSession } from "@fluixi/session";
|
|
7
7
|
import { createAuthHooks } from "@fluixi/auth/client";
|
|
8
8
|
|
|
@@ -112,7 +112,7 @@ function resolveMethod(auth) {
|
|
|
112
112
|
}
|
|
113
113
|
async function loadJose() {
|
|
114
114
|
try {
|
|
115
|
-
return await import("./browser-
|
|
115
|
+
return await import("./browser-VTMW33ZW.mjs");
|
|
116
116
|
} catch {
|
|
117
117
|
throw new OAuthError(
|
|
118
118
|
"private_key_jwt needs `jose`. Install it: npm i jose. It is an optional peer, so a client using a secret does not carry it.",
|
|
@@ -152,7 +152,7 @@ async function applyClientAuth(auth, endpoint, headers, form) {
|
|
|
152
152
|
// src/dpop.ts
|
|
153
153
|
async function loadJose2() {
|
|
154
154
|
try {
|
|
155
|
-
return await import("./browser-
|
|
155
|
+
return await import("./browser-VTMW33ZW.mjs");
|
|
156
156
|
} catch {
|
|
157
157
|
throw new OAuthError(
|
|
158
158
|
"DPoP needs `jose`. Install it: npm i jose. It is an optional peer, so a client not using DPoP does not carry it.",
|
|
@@ -310,8 +310,12 @@ async function discover(issuer, fetcher = fetch) {
|
|
|
310
310
|
try {
|
|
311
311
|
response = await fetcher(documentUrl(issuer));
|
|
312
312
|
} catch (cause) {
|
|
313
|
+
const why = cause instanceof Error ? cause.message : String(cause);
|
|
313
314
|
throw new OAuthError(
|
|
314
|
-
|
|
315
|
+
typeof window === "undefined" ? (
|
|
316
|
+
// On a server nothing blocks the read: the provider is down, or the address is wrong.
|
|
317
|
+
`Could not reach the provider at ${documentUrl(issuer)}: is it running, and is the issuer right? (${why})`
|
|
318
|
+
) : `Could not read the discovery document at ${documentUrl(issuer)}. In a browser this is usually the provider refusing a cross-origin read: give \`endpoints\` directly, or resolve them on a server. (${why})`,
|
|
315
319
|
"discovery_unreachable"
|
|
316
320
|
);
|
|
317
321
|
}
|
|
@@ -336,6 +340,7 @@ async function discover(issuer, fetcher = fetch) {
|
|
|
336
340
|
jwks: doc.jwks_uri,
|
|
337
341
|
introspection: doc.introspection_endpoint,
|
|
338
342
|
revocation: doc.revocation_endpoint,
|
|
343
|
+
checkSession: doc.check_session_iframe,
|
|
339
344
|
issuer: doc.issuer ?? issuer
|
|
340
345
|
};
|
|
341
346
|
})();
|
|
@@ -794,6 +799,81 @@ function createServerClient(config, fetcher = fetch) {
|
|
|
794
799
|
};
|
|
795
800
|
}
|
|
796
801
|
|
|
802
|
+
// src/session-monitor.ts
|
|
803
|
+
var SETTLE_MS = 15e3;
|
|
804
|
+
var GUARD_KEY = "fx-session-check";
|
|
805
|
+
function recentlyActed() {
|
|
806
|
+
try {
|
|
807
|
+
return Date.now() - Number(sessionStorage.getItem(GUARD_KEY) ?? 0) < SETTLE_MS;
|
|
808
|
+
} catch {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
function markActed() {
|
|
813
|
+
try {
|
|
814
|
+
sessionStorage.setItem(GUARD_KEY, String(Date.now()));
|
|
815
|
+
} catch {
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
function watchProviderSession(options = {}) {
|
|
819
|
+
if (typeof window === "undefined" || typeof document === "undefined") return () => {
|
|
820
|
+
};
|
|
821
|
+
const base = (options.basePath ?? "/auth").replace(/\/$/, "");
|
|
822
|
+
const fetcher = options.fetcher ?? fetch;
|
|
823
|
+
const onChange = options.onChange ?? (() => {
|
|
824
|
+
const login = new URLSearchParams({ prompt: "none", returnTo: location.pathname + location.search });
|
|
825
|
+
location.assign(`${base}/login?${login}`);
|
|
826
|
+
});
|
|
827
|
+
let stopped = false;
|
|
828
|
+
const cleanups = [];
|
|
829
|
+
const stop = () => {
|
|
830
|
+
stopped = true;
|
|
831
|
+
for (const cleanup of cleanups.splice(0)) cleanup();
|
|
832
|
+
};
|
|
833
|
+
void (async () => {
|
|
834
|
+
const check = await fetcher(`${base}/session-check`, { credentials: "same-origin" }).then((response) => response.ok ? response.json() : null).catch(() => null);
|
|
835
|
+
if (stopped || !check?.frame || !check.state) return;
|
|
836
|
+
const origin = new URL(check.frame).origin;
|
|
837
|
+
const frame = document.createElement("iframe");
|
|
838
|
+
frame.src = check.frame;
|
|
839
|
+
frame.title = "session check";
|
|
840
|
+
frame.setAttribute("aria-hidden", "true");
|
|
841
|
+
frame.tabIndex = -1;
|
|
842
|
+
frame.style.cssText = "position:absolute;width:0;height:0;border:0;visibility:hidden";
|
|
843
|
+
const message = `${check.clientId} ${check.state}`;
|
|
844
|
+
const ask = () => {
|
|
845
|
+
if (!stopped && document.visibilityState === "visible") frame.contentWindow?.postMessage(message, origin);
|
|
846
|
+
};
|
|
847
|
+
let confirmed = false;
|
|
848
|
+
const answer = (event) => {
|
|
849
|
+
if (event.origin !== origin || event.source !== frame.contentWindow) return;
|
|
850
|
+
if (event.data === "unchanged") confirmed = true;
|
|
851
|
+
else if (event.data === "changed") {
|
|
852
|
+
stop();
|
|
853
|
+
if (!confirmed && recentlyActed()) return;
|
|
854
|
+
markActed();
|
|
855
|
+
onChange();
|
|
856
|
+
} else if (event.data === "error") {
|
|
857
|
+
stop();
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
window.addEventListener("message", answer);
|
|
861
|
+
frame.addEventListener("load", ask);
|
|
862
|
+
document.addEventListener("visibilitychange", ask);
|
|
863
|
+
window.addEventListener("focus", ask);
|
|
864
|
+
const timer = setInterval(ask, options.intervalMs ?? 3e3);
|
|
865
|
+
document.body.appendChild(frame);
|
|
866
|
+
cleanups.push(() => {
|
|
867
|
+
window.removeEventListener("message", answer);
|
|
868
|
+
document.removeEventListener("visibilitychange", ask);
|
|
869
|
+
window.removeEventListener("focus", ask);
|
|
870
|
+
clearInterval(timer);
|
|
871
|
+
frame.remove();
|
|
872
|
+
});
|
|
873
|
+
})();
|
|
874
|
+
return stop;
|
|
875
|
+
}
|
|
876
|
+
|
|
797
877
|
// src/service.ts
|
|
798
878
|
function paramsFromUrl(url) {
|
|
799
879
|
const href = url ?? (typeof location === "undefined" ? null : location.href);
|
|
@@ -820,16 +900,19 @@ function createAuthService(options) {
|
|
|
820
900
|
function buildAuthService(options) {
|
|
821
901
|
const client = clientFor(options);
|
|
822
902
|
let latest = null;
|
|
903
|
+
const fetchUserFor = async (token) => {
|
|
904
|
+
if (options.fetchUser) return options.fetchUser(token);
|
|
905
|
+
return client.fetchUser(token === COOKIE_SESSION ? void 0 : token);
|
|
906
|
+
};
|
|
907
|
+
const resumesFromCookie = options.config.tokens === "server" && typeof window !== "undefined";
|
|
908
|
+
const [ready, setReady] = createSignal(!resumesFromCookie);
|
|
823
909
|
const session = createSession({
|
|
824
910
|
/** The credential is the callback, so this is the code exchange. */
|
|
825
911
|
async login(params) {
|
|
826
912
|
latest = await client.handleCallback(params);
|
|
827
913
|
return { token: latest.accessToken, expiresAt: latest.expiresAt };
|
|
828
914
|
},
|
|
829
|
-
|
|
830
|
-
if (options.fetchUser) return options.fetchUser(token);
|
|
831
|
-
return client.fetchUser(token === COOKIE_SESSION ? void 0 : token);
|
|
832
|
-
},
|
|
915
|
+
fetchUser: fetchUserFor,
|
|
833
916
|
async refresh() {
|
|
834
917
|
latest = await client.refresh();
|
|
835
918
|
return { token: latest.accessToken, expiresAt: latest.expiresAt };
|
|
@@ -852,11 +935,27 @@ function buildAuthService(options) {
|
|
|
852
935
|
});
|
|
853
936
|
const hooks = createAuthHooks({
|
|
854
937
|
session,
|
|
938
|
+
ready,
|
|
855
939
|
navigate: options.navigate,
|
|
856
940
|
loginPath: options.loginPath ?? "/login",
|
|
857
941
|
homePath: options.homePath ?? "/",
|
|
858
942
|
forbiddenPath: options.forbiddenPath ?? "/403"
|
|
859
943
|
});
|
|
944
|
+
if (resumesFromCookie && options.config.tokens === "server" && options.config.watchSession !== false) {
|
|
945
|
+
watchProviderSession({ basePath: options.config.basePath });
|
|
946
|
+
}
|
|
947
|
+
const renderedSignedOut = hooks.store.seeded && hooks.store.value().user == null;
|
|
948
|
+
if (resumesFromCookie && renderedSignedOut) setReady(true);
|
|
949
|
+
else if (resumesFromCookie) {
|
|
950
|
+
void (async () => {
|
|
951
|
+
try {
|
|
952
|
+
await session.adopt(COOKIE_SESSION, await fetchUserFor(COOKIE_SESSION));
|
|
953
|
+
} catch {
|
|
954
|
+
} finally {
|
|
955
|
+
setReady(true);
|
|
956
|
+
}
|
|
957
|
+
})();
|
|
958
|
+
}
|
|
860
959
|
return Object.assign(session, {
|
|
861
960
|
client,
|
|
862
961
|
protectedRoute: hooks.protectedRoute,
|
|
@@ -930,5 +1029,6 @@ export {
|
|
|
930
1029
|
paramsFromUrl,
|
|
931
1030
|
proofFor,
|
|
932
1031
|
safeReturnTo,
|
|
933
|
-
thumbprintOf
|
|
1032
|
+
thumbprintOf,
|
|
1033
|
+
watchProviderSession
|
|
934
1034
|
};
|