oidc-spa 8.2.2 → 8.2.4
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/core/Oidc.d.ts +1 -0
- package/core/createOidc.d.ts +48 -16
- package/core/createOidc.js +27 -36
- package/core/createOidc.js.map +1 -1
- package/core/desiredPostLoginRedirectUrl.d.ts +4 -0
- package/core/desiredPostLoginRedirectUrl.js +12 -0
- package/core/desiredPostLoginRedirectUrl.js.map +1 -0
- package/core/diagnostic.d.ts +1 -1
- package/core/diagnostic.js +3 -3
- package/core/diagnostic.js.map +1 -1
- package/core/homeAndRedirectUri.d.ts +5 -0
- package/core/homeAndRedirectUri.js +32 -0
- package/core/homeAndRedirectUri.js.map +1 -0
- package/esm/angular.d.ts +28 -4
- package/esm/angular.js +31 -6
- package/esm/angular.js.map +1 -1
- package/esm/core/Oidc.d.ts +1 -0
- package/esm/core/createOidc.d.ts +48 -16
- package/esm/core/createOidc.js +27 -36
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/desiredPostLoginRedirectUrl.d.ts +4 -0
- package/esm/core/desiredPostLoginRedirectUrl.js +8 -0
- package/esm/core/desiredPostLoginRedirectUrl.js.map +1 -0
- package/esm/core/diagnostic.d.ts +1 -1
- package/esm/core/diagnostic.js +3 -3
- package/esm/core/diagnostic.js.map +1 -1
- package/esm/core/homeAndRedirectUri.d.ts +5 -0
- package/esm/core/homeAndRedirectUri.js +29 -0
- package/esm/core/homeAndRedirectUri.js.map +1 -0
- package/esm/keycloak/keycloak-js/Keycloak.d.ts +40 -0
- package/esm/keycloak/keycloak-js/Keycloak.js +13 -3
- package/esm/keycloak/keycloak-js/Keycloak.js.map +1 -1
- package/esm/keycloak/keycloakUtils.d.ts +3 -1
- package/esm/keycloak/keycloakUtils.js +26 -5
- package/esm/keycloak/keycloakUtils.js.map +1 -1
- package/esm/mock/oidc.js +2 -1
- package/esm/mock/oidc.js.map +1 -1
- package/esm/react/react.js +24 -2
- package/esm/react/react.js.map +1 -1
- package/esm/react-spa/apiBuilder.d.ts +2 -2
- package/esm/react-spa/apiBuilder.js +1 -1
- package/esm/react-spa/apiBuilder.js.map +1 -1
- package/esm/react-spa/createOidcSpaApi.js +29 -5
- package/esm/react-spa/createOidcSpaApi.js.map +1 -1
- package/esm/react-spa/types.d.ts +27 -3
- package/esm/tanstack-start/react/apiBuilder.d.ts +2 -2
- package/esm/tanstack-start/react/apiBuilder.js +1 -1
- package/esm/tanstack-start/react/apiBuilder.js.map +1 -1
- package/esm/tanstack-start/react/createOidcSpaApi.js +28 -4
- package/esm/tanstack-start/react/createOidcSpaApi.js.map +1 -1
- package/esm/tanstack-start/react/types.d.ts +27 -3
- package/esm/tools/lazySessionStorage.d.ts +3 -1
- package/esm/tools/lazySessionStorage.js +8 -6
- package/esm/tools/lazySessionStorage.js.map +1 -1
- package/esm/tools/parseKeycloakIssuerUri.js +5 -1
- package/esm/tools/parseKeycloakIssuerUri.js.map +1 -1
- package/keycloak/keycloak-js/Keycloak.d.ts +40 -0
- package/keycloak/keycloak-js/Keycloak.js +13 -3
- package/keycloak/keycloak-js/Keycloak.js.map +1 -1
- package/keycloak/keycloakUtils.d.ts +3 -1
- package/keycloak/keycloakUtils.js +26 -5
- package/keycloak/keycloakUtils.js.map +1 -1
- package/mock/oidc.js +2 -1
- package/mock/oidc.js.map +1 -1
- package/package.json +5 -1
- package/react/react.js +24 -2
- package/react/react.js.map +1 -1
- package/react-spa/apiBuilder.d.ts +2 -2
- package/react-spa/apiBuilder.js +1 -1
- package/react-spa/apiBuilder.js.map +1 -1
- package/react-spa/createOidcSpaApi.js +29 -5
- package/react-spa/createOidcSpaApi.js.map +1 -1
- package/react-spa/types.d.ts +27 -3
- package/src/angular.ts +76 -18
- package/src/core/Oidc.ts +1 -0
- package/src/core/createOidc.ts +78 -57
- package/src/core/desiredPostLoginRedirectUrl.ts +9 -0
- package/src/core/diagnostic.ts +4 -4
- package/src/core/homeAndRedirectUri.ts +36 -0
- package/src/keycloak/keycloak-js/Keycloak.ts +56 -3
- package/src/keycloak/keycloakUtils.ts +38 -6
- package/src/mock/oidc.ts +2 -1
- package/src/react/react.tsx +32 -3
- package/src/react-spa/apiBuilder.ts +3 -3
- package/src/react-spa/createOidcSpaApi.tsx +37 -6
- package/src/react-spa/types.tsx +27 -3
- package/src/tanstack-start/react/apiBuilder.ts +3 -3
- package/src/tanstack-start/react/createOidcSpaApi.tsx +36 -5
- package/src/tanstack-start/react/types.tsx +27 -3
- package/src/tools/lazySessionStorage.ts +11 -7
- package/src/tools/parseKeycloakIssuerUri.ts +6 -1
- package/src/vite-plugin/manageOptimizedDeps.ts +2 -1
- package/tools/lazySessionStorage.d.ts +3 -1
- package/tools/lazySessionStorage.js +8 -6
- package/tools/lazySessionStorage.js.map +1 -1
- package/tools/parseKeycloakIssuerUri.js +5 -1
- package/tools/parseKeycloakIssuerUri.js.map +1 -1
- package/vite-plugin/manageOptimizedDeps.js +2 -1
- package/vite-plugin/manageOptimizedDeps.js.map +1 -1
package/src/react/react.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import { id } from "../tools/tsafe/id";
|
|
|
15
15
|
import type { ValueOrAsyncGetter } from "../tools/ValueOrAsyncGetter";
|
|
16
16
|
import { Deferred } from "../tools/Deferred";
|
|
17
17
|
import { toFullyQualifiedUrl } from "../tools/toFullyQualifiedUrl";
|
|
18
|
+
import { setDesiredPostLoginRedirectUrl } from "../core/desiredPostLoginRedirectUrl";
|
|
18
19
|
|
|
19
20
|
export type OidcReact<DecodedIdToken extends Record<string, unknown>> =
|
|
20
21
|
| OidcReact.NotLoggedIn
|
|
@@ -409,20 +410,48 @@ export function createReactOidc_dependencyInjection<
|
|
|
409
410
|
|
|
410
411
|
const oidc = await getOidc();
|
|
411
412
|
|
|
413
|
+
const isUrlAlreadyReplaced =
|
|
414
|
+
window.location.href.replace(/\/$/, "") === redirectUrl.replace(/\/$/, "");
|
|
415
|
+
|
|
412
416
|
if (!oidc.isUserLoggedIn) {
|
|
413
417
|
if (cause === "preload") {
|
|
414
418
|
throw new Error(
|
|
415
419
|
"oidc-spa: User is not yet logged in. This is an expected error, nothing to be addressed."
|
|
416
420
|
);
|
|
417
421
|
}
|
|
418
|
-
const doesCurrentHrefRequiresAuth =
|
|
419
|
-
location.href.replace(/\/$/, "") === redirectUrl.replace(/\/$/, "");
|
|
420
422
|
|
|
421
423
|
await oidc.login({
|
|
422
424
|
redirectUrl,
|
|
423
|
-
doesCurrentHrefRequiresAuth
|
|
425
|
+
doesCurrentHrefRequiresAuth: isUrlAlreadyReplaced
|
|
424
426
|
});
|
|
425
427
|
}
|
|
428
|
+
|
|
429
|
+
define_temporary_postLoginRedirectUrl: {
|
|
430
|
+
if (isUrlAlreadyReplaced) {
|
|
431
|
+
break define_temporary_postLoginRedirectUrl;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
setDesiredPostLoginRedirectUrl({ postLoginRedirectUrl: redirectUrl });
|
|
435
|
+
|
|
436
|
+
const history_pushState = history.pushState;
|
|
437
|
+
const history_replaceState = history.replaceState;
|
|
438
|
+
|
|
439
|
+
const onNavigated = () => {
|
|
440
|
+
history.pushState = history_pushState;
|
|
441
|
+
history.replaceState = history_replaceState;
|
|
442
|
+
setDesiredPostLoginRedirectUrl({ postLoginRedirectUrl: undefined });
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
history.pushState = function pushState(...args) {
|
|
446
|
+
onNavigated();
|
|
447
|
+
return history_pushState.call(history, ...args);
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
history.replaceState = function replaceState(...args) {
|
|
451
|
+
onNavigated();
|
|
452
|
+
return history_replaceState.call(history, ...args);
|
|
453
|
+
};
|
|
454
|
+
}
|
|
426
455
|
}
|
|
427
456
|
|
|
428
457
|
async function getOidc(): Promise<Oidc<DecodedIdToken>> {
|
|
@@ -10,7 +10,7 @@ export type OidcSpaApiBuilder<
|
|
|
10
10
|
| "withAutoLogin"
|
|
11
11
|
| "withExpectedDecodedIdTokenShape"
|
|
12
12
|
| "withAccessTokenValidation"
|
|
13
|
-
| "
|
|
13
|
+
| "createApi" = never
|
|
14
14
|
> = Omit<
|
|
15
15
|
{
|
|
16
16
|
withAutoLogin: () => OidcSpaApiBuilder<true, DecodedIdToken, ExcludedMethod | "withAutoLogin">;
|
|
@@ -26,7 +26,7 @@ export type OidcSpaApiBuilder<
|
|
|
26
26
|
ExcludedMethod | "withExpectedDecodedIdTokenShape"
|
|
27
27
|
>;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
createApi: () => OidcSpaApi<AutoLogin, DecodedIdToken>;
|
|
30
30
|
},
|
|
31
31
|
ExcludedMethod
|
|
32
32
|
>;
|
|
@@ -54,7 +54,7 @@ function createOidcSpaApiBuilder<
|
|
|
54
54
|
decodedIdTokenSchema,
|
|
55
55
|
decodedIdToken_mock: decodedIdToken_mock
|
|
56
56
|
}),
|
|
57
|
-
|
|
57
|
+
createApi: () =>
|
|
58
58
|
createOidcSpaApi<AutoLogin, DecodedIdToken>({
|
|
59
59
|
autoLogin: params.autoLogin,
|
|
60
60
|
decodedIdTokenSchema: params.decodedIdTokenSchema,
|
|
@@ -10,6 +10,7 @@ import { createObjectThatThrowsIfAccessed } from "../tools/createObjectThatThrow
|
|
|
10
10
|
import { createStatefulEvt } from "../tools/StatefulEvt";
|
|
11
11
|
import { id } from "../tools/tsafe/id";
|
|
12
12
|
import { toFullyQualifiedUrl } from "../tools/toFullyQualifiedUrl";
|
|
13
|
+
import { setDesiredPostLoginRedirectUrl } from "../core/desiredPostLoginRedirectUrl";
|
|
13
14
|
|
|
14
15
|
export function createOidcSpaApi<
|
|
15
16
|
AutoLogin extends boolean,
|
|
@@ -225,6 +226,7 @@ export function createOidcSpaApi<
|
|
|
225
226
|
initializationError: oidcCore.initializationError,
|
|
226
227
|
issuerUri: oidcCore.params.issuerUri,
|
|
227
228
|
clientId: oidcCore.params.clientId,
|
|
229
|
+
validRedirectUri: oidcCore.params.validRedirectUri,
|
|
228
230
|
autoLogoutState: { shouldDisplayWarning: false },
|
|
229
231
|
login: params =>
|
|
230
232
|
oidcCore.login({
|
|
@@ -250,7 +252,8 @@ export function createOidcSpaApi<
|
|
|
250
252
|
return evtAutoLogoutState.current;
|
|
251
253
|
},
|
|
252
254
|
issuerUri: oidcCore.params.issuerUri,
|
|
253
|
-
clientId: oidcCore.params.clientId
|
|
255
|
+
clientId: oidcCore.params.clientId,
|
|
256
|
+
validRedirectUri: oidcCore.params.validRedirectUri
|
|
254
257
|
});
|
|
255
258
|
}
|
|
256
259
|
|
|
@@ -390,7 +393,7 @@ export function createOidcSpaApi<
|
|
|
390
393
|
transformUrlBeforeRedirect: paramsOfBootstrap.transformUrlBeforeRedirect,
|
|
391
394
|
extraQueryParams: paramsOfBootstrap.extraQueryParams,
|
|
392
395
|
extraTokenParams: paramsOfBootstrap.extraTokenParams,
|
|
393
|
-
|
|
396
|
+
sessionRestorationMethod: paramsOfBootstrap.sessionRestorationMethod,
|
|
394
397
|
debugLogs: paramsOfBootstrap.debugLogs,
|
|
395
398
|
__unsafe_clientSecret: paramsOfBootstrap.__unsafe_clientSecret,
|
|
396
399
|
__metadata: paramsOfBootstrap.__metadata,
|
|
@@ -440,25 +443,53 @@ export function createOidcSpaApi<
|
|
|
440
443
|
});
|
|
441
444
|
}
|
|
442
445
|
|
|
443
|
-
return location.href;
|
|
446
|
+
return window.location.href;
|
|
444
447
|
})();
|
|
445
448
|
|
|
446
449
|
const oidc = await getOidc();
|
|
447
450
|
|
|
451
|
+
const isUrlAlreadyReplaced =
|
|
452
|
+
window.location.href.replace(/\/$/, "") === redirectUrl.replace(/\/$/, "");
|
|
453
|
+
|
|
448
454
|
if (!oidc.isUserLoggedIn) {
|
|
449
455
|
if (cause === "preload") {
|
|
450
456
|
throw new Error(
|
|
451
457
|
"oidc-spa: User is not yet logged in. This is an expected error, nothing to be addressed."
|
|
452
458
|
);
|
|
453
459
|
}
|
|
454
|
-
const doesCurrentHrefRequiresAuth =
|
|
455
|
-
location.href.replace(/\/$/, "") === redirectUrl.replace(/\/$/, "");
|
|
456
460
|
|
|
457
461
|
await oidc.login({
|
|
458
462
|
redirectUrl,
|
|
459
|
-
doesCurrentHrefRequiresAuth
|
|
463
|
+
doesCurrentHrefRequiresAuth: isUrlAlreadyReplaced
|
|
460
464
|
});
|
|
461
465
|
}
|
|
466
|
+
|
|
467
|
+
define_temporary_postLoginRedirectUrl: {
|
|
468
|
+
if (isUrlAlreadyReplaced) {
|
|
469
|
+
break define_temporary_postLoginRedirectUrl;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
setDesiredPostLoginRedirectUrl({ postLoginRedirectUrl: redirectUrl });
|
|
473
|
+
|
|
474
|
+
const history_pushState = history.pushState;
|
|
475
|
+
const history_replaceState = history.replaceState;
|
|
476
|
+
|
|
477
|
+
const onNavigated = () => {
|
|
478
|
+
history.pushState = history_pushState;
|
|
479
|
+
history.replaceState = history_replaceState;
|
|
480
|
+
setDesiredPostLoginRedirectUrl({ postLoginRedirectUrl: undefined });
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
history.pushState = function pushState(...args) {
|
|
484
|
+
onNavigated();
|
|
485
|
+
return history_pushState.call(history, ...args);
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
history.replaceState = function replaceState(...args) {
|
|
489
|
+
onNavigated();
|
|
490
|
+
return history_replaceState.call(history, ...args);
|
|
491
|
+
};
|
|
492
|
+
}
|
|
462
493
|
}
|
|
463
494
|
|
|
464
495
|
function OidcInitializationErrorGate(props: {
|
package/src/react-spa/types.tsx
CHANGED
|
@@ -31,6 +31,7 @@ export namespace UseOidc {
|
|
|
31
31
|
type Common = {
|
|
32
32
|
issuerUri: string;
|
|
33
33
|
clientId: string;
|
|
34
|
+
validRedirectUri: string;
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export type NotLoggedIn = Common & {
|
|
@@ -213,11 +214,34 @@ export namespace ParamsOfBootstrap {
|
|
|
213
214
|
| (() => Record<string, string | undefined>);
|
|
214
215
|
|
|
215
216
|
/**
|
|
216
|
-
*
|
|
217
|
+
* Determines how session restoration is handled.
|
|
218
|
+
* Session restoration allows users to stay logged in between visits
|
|
219
|
+
* without needing to explicitly sign in each time.
|
|
217
220
|
*
|
|
218
|
-
*
|
|
221
|
+
* Options:
|
|
222
|
+
*
|
|
223
|
+
* - **"auto" (default)**:
|
|
224
|
+
* Automatically selects the best method.
|
|
225
|
+
* If the app’s domain shares a common parent domain with the authorization endpoint,
|
|
226
|
+
* an iframe is used for silent session restoration.
|
|
227
|
+
* Otherwise, a full-page redirect is used.
|
|
228
|
+
*
|
|
229
|
+
* - **"full page redirect"**:
|
|
230
|
+
* Forces full-page reloads for session restoration.
|
|
231
|
+
* Use this if your application is served with a restrictive CSP
|
|
232
|
+
* (e.g., `Content-Security-Policy: frame-ancestors "none"`)
|
|
233
|
+
* or `X-Frame-Options: DENY`, and you cannot modify those headers.
|
|
234
|
+
* This mode provides a slightly less seamless UX and will lead oidc-spa to
|
|
235
|
+
* store tokens in `localStorage` if multiple OIDC clients are used
|
|
236
|
+
* (e.g., your app communicates with several APIs).
|
|
237
|
+
*
|
|
238
|
+
* - **"iframe"**:
|
|
239
|
+
* Forces iframe-based session restoration.
|
|
240
|
+
* In development, if you go in your browser setting and allow your auth server’s domain
|
|
241
|
+
* to set third-party cookies this value will let you test your app
|
|
242
|
+
* with the local dev server as it will behave in production.
|
|
219
243
|
*/
|
|
220
|
-
|
|
244
|
+
sessionRestorationMethod?: "iframe" | "full page redirect" | "auto";
|
|
221
245
|
|
|
222
246
|
debugLogs?: boolean;
|
|
223
247
|
|
|
@@ -14,7 +14,7 @@ export type OidcSpaApiBuilder<
|
|
|
14
14
|
| "withAutoLogin"
|
|
15
15
|
| "withExpectedDecodedIdTokenShape"
|
|
16
16
|
| "withAccessTokenValidation"
|
|
17
|
-
| "
|
|
17
|
+
| "createApi" = never
|
|
18
18
|
> = Omit<
|
|
19
19
|
{
|
|
20
20
|
withAutoLogin: () => OidcSpaApiBuilder<
|
|
@@ -61,7 +61,7 @@ export type OidcSpaApiBuilder<
|
|
|
61
61
|
ExcludedMethod | "withAccessTokenValidation"
|
|
62
62
|
>;
|
|
63
63
|
};
|
|
64
|
-
|
|
64
|
+
createApi: () => OidcSpaApi<AutoLogin, DecodedIdToken, AccessTokenClaims>;
|
|
65
65
|
},
|
|
66
66
|
ExcludedMethod
|
|
67
67
|
>;
|
|
@@ -127,7 +127,7 @@ function createOidcSpaApiBuilder<
|
|
|
127
127
|
}
|
|
128
128
|
})()
|
|
129
129
|
}),
|
|
130
|
-
|
|
130
|
+
createApi: () =>
|
|
131
131
|
createOidcSpaApi<AutoLogin, DecodedIdToken, AccessTokenClaims>({
|
|
132
132
|
autoLogin: params.autoLogin,
|
|
133
133
|
decodedIdTokenSchema: params.decodedIdTokenSchema,
|
|
@@ -30,6 +30,7 @@ import { createServerFn, createMiddleware } from "@tanstack/react-start";
|
|
|
30
30
|
import { getRequest, setResponseHeader, setResponseStatus } from "@tanstack/react-start/server";
|
|
31
31
|
import { toFullyQualifiedUrl } from "../../tools/toFullyQualifiedUrl";
|
|
32
32
|
import { UnifiedClientRetryForSsrLoadersError } from "./rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError";
|
|
33
|
+
import { setDesiredPostLoginRedirectUrl } from "../../core/desiredPostLoginRedirectUrl";
|
|
33
34
|
|
|
34
35
|
export function createOidcSpaApi<
|
|
35
36
|
AutoLogin extends boolean,
|
|
@@ -215,6 +216,7 @@ export function createOidcSpaApi<
|
|
|
215
216
|
initializationError: oidcCore.initializationError,
|
|
216
217
|
issuerUri: oidcCore.params.issuerUri,
|
|
217
218
|
clientId: oidcCore.params.clientId,
|
|
219
|
+
validRedirectUri: oidcCore.params.validRedirectUri,
|
|
218
220
|
autoLogoutState: { shouldDisplayWarning: false },
|
|
219
221
|
login: params =>
|
|
220
222
|
oidcCore.login({
|
|
@@ -240,7 +242,8 @@ export function createOidcSpaApi<
|
|
|
240
242
|
return evtAutoLogoutState.current;
|
|
241
243
|
},
|
|
242
244
|
issuerUri: oidcCore.params.issuerUri,
|
|
243
|
-
clientId: oidcCore.params.clientId
|
|
245
|
+
clientId: oidcCore.params.clientId,
|
|
246
|
+
validRedirectUri: oidcCore.params.validRedirectUri
|
|
244
247
|
});
|
|
245
248
|
}
|
|
246
249
|
|
|
@@ -662,7 +665,7 @@ export function createOidcSpaApi<
|
|
|
662
665
|
transformUrlBeforeRedirect: paramsOfBootstrap.transformUrlBeforeRedirect,
|
|
663
666
|
extraQueryParams: paramsOfBootstrap.extraQueryParams,
|
|
664
667
|
extraTokenParams: paramsOfBootstrap.extraTokenParams,
|
|
665
|
-
|
|
668
|
+
sessionRestorationMethod: paramsOfBootstrap.sessionRestorationMethod,
|
|
666
669
|
debugLogs: paramsOfBootstrap.debugLogs,
|
|
667
670
|
__unsafe_clientSecret: paramsOfBootstrap.__unsafe_clientSecret,
|
|
668
671
|
__metadata: paramsOfBootstrap.__metadata,
|
|
@@ -714,6 +717,9 @@ export function createOidcSpaApi<
|
|
|
714
717
|
|
|
715
718
|
const oidc = await getOidc();
|
|
716
719
|
|
|
720
|
+
const isUrlAlreadyReplaced =
|
|
721
|
+
window.location.href.replace(/\/$/, "") === redirectUrl.replace(/\/$/, "");
|
|
722
|
+
|
|
717
723
|
if (!oidc.isUserLoggedIn) {
|
|
718
724
|
if (cause === "preload") {
|
|
719
725
|
throw new Error(
|
|
@@ -724,14 +730,39 @@ export function createOidcSpaApi<
|
|
|
724
730
|
].join(" ")
|
|
725
731
|
);
|
|
726
732
|
}
|
|
727
|
-
const doesCurrentHrefRequiresAuth =
|
|
728
|
-
location.href.replace(/\/$/, "") === redirectUrl.replace(/\/$/, "");
|
|
729
733
|
|
|
730
734
|
await oidc.login({
|
|
731
735
|
redirectUrl,
|
|
732
|
-
doesCurrentHrefRequiresAuth
|
|
736
|
+
doesCurrentHrefRequiresAuth: isUrlAlreadyReplaced
|
|
733
737
|
});
|
|
734
738
|
}
|
|
739
|
+
|
|
740
|
+
define_temporary_postLoginRedirectUrl: {
|
|
741
|
+
if (isUrlAlreadyReplaced) {
|
|
742
|
+
break define_temporary_postLoginRedirectUrl;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
setDesiredPostLoginRedirectUrl({ postLoginRedirectUrl: redirectUrl });
|
|
746
|
+
|
|
747
|
+
const history_pushState = history.pushState;
|
|
748
|
+
const history_replaceState = history.replaceState;
|
|
749
|
+
|
|
750
|
+
const onNavigated = () => {
|
|
751
|
+
history.pushState = history_pushState;
|
|
752
|
+
history.replaceState = history_replaceState;
|
|
753
|
+
setDesiredPostLoginRedirectUrl({ postLoginRedirectUrl: undefined });
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
history.pushState = function pushState(...args) {
|
|
757
|
+
onNavigated();
|
|
758
|
+
return history_pushState.call(history, ...args);
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
history.replaceState = function replaceState(...args) {
|
|
762
|
+
onNavigated();
|
|
763
|
+
return history_replaceState.call(history, ...args);
|
|
764
|
+
};
|
|
765
|
+
}
|
|
735
766
|
}
|
|
736
767
|
|
|
737
768
|
enforceLogin.__isOidcSpaEnforceLogin = true;
|
|
@@ -45,6 +45,7 @@ export namespace CreateOidcComponent {
|
|
|
45
45
|
type Common = {
|
|
46
46
|
issuerUri: string;
|
|
47
47
|
clientId: string;
|
|
48
|
+
validRedirectUri: string;
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
export type NotLoggedIn = Common & {
|
|
@@ -306,11 +307,34 @@ export namespace ParamsOfBootstrap {
|
|
|
306
307
|
| (() => Record<string, string | undefined>);
|
|
307
308
|
|
|
308
309
|
/**
|
|
309
|
-
*
|
|
310
|
+
* Determines how session restoration is handled.
|
|
311
|
+
* Session restoration allows users to stay logged in between visits
|
|
312
|
+
* without needing to explicitly sign in each time.
|
|
310
313
|
*
|
|
311
|
-
*
|
|
314
|
+
* Options:
|
|
315
|
+
*
|
|
316
|
+
* - **"auto" (default)**:
|
|
317
|
+
* Automatically selects the best method.
|
|
318
|
+
* If the app’s domain shares a common parent domain with the authorization endpoint,
|
|
319
|
+
* an iframe is used for silent session restoration.
|
|
320
|
+
* Otherwise, a full-page redirect is used.
|
|
321
|
+
*
|
|
322
|
+
* - **"full page redirect"**:
|
|
323
|
+
* Forces full-page reloads for session restoration.
|
|
324
|
+
* Use this if your application is served with a restrictive CSP
|
|
325
|
+
* (e.g., `Content-Security-Policy: frame-ancestors "none"`)
|
|
326
|
+
* or `X-Frame-Options: DENY`, and you cannot modify those headers.
|
|
327
|
+
* This mode provides a slightly less seamless UX and will lead oidc-spa to
|
|
328
|
+
* store tokens in `localStorage` if multiple OIDC clients are used
|
|
329
|
+
* (e.g., your app communicates with several APIs).
|
|
330
|
+
*
|
|
331
|
+
* - **"iframe"**:
|
|
332
|
+
* Forces iframe-based session restoration.
|
|
333
|
+
* In development, if you go in your browser setting and allow your auth server’s domain
|
|
334
|
+
* to set third-party cookies this value will let you test your app
|
|
335
|
+
* with the local dev server as it will behave in production.
|
|
312
336
|
*/
|
|
313
|
-
|
|
337
|
+
sessionRestorationMethod?: "iframe" | "full page redirect" | "auto";
|
|
314
338
|
|
|
315
339
|
debugLogs?: boolean;
|
|
316
340
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { assert } from "../tools/tsafe/assert";
|
|
2
2
|
|
|
3
|
-
const SESSION_STORAGE_PREFIX = "lazy-session-storage:";
|
|
4
|
-
|
|
5
3
|
export type LazySessionStorage = {
|
|
6
4
|
// `Storage` methods, we don't use the type directly because it has [name: string]: any;
|
|
7
5
|
readonly length: number;
|
|
@@ -15,14 +13,20 @@ export type LazySessionStorage = {
|
|
|
15
13
|
persistCurrentStateAndSubsequentChanges: () => void;
|
|
16
14
|
};
|
|
17
15
|
|
|
18
|
-
export function createLazySessionStorage(): LazySessionStorage {
|
|
16
|
+
export function createLazySessionStorage(params: { storageId: string }): LazySessionStorage {
|
|
17
|
+
const { storageId } = params;
|
|
18
|
+
|
|
19
|
+
const sessionStoragePrefix = `lazy-session-storage:${storageId}:`;
|
|
20
|
+
|
|
21
|
+
const getSessionStorageKey = (key: string) => `${sessionStoragePrefix}${key}`;
|
|
22
|
+
|
|
19
23
|
const entries: { key: string; value: string }[] = [];
|
|
20
24
|
|
|
21
25
|
for (let i = 0; i < sessionStorage.length; i++) {
|
|
22
26
|
const key = sessionStorage.key(i);
|
|
23
27
|
assert(key !== null, "470498");
|
|
24
28
|
|
|
25
|
-
if (!key.startsWith(
|
|
29
|
+
if (!key.startsWith(sessionStoragePrefix)) {
|
|
26
30
|
continue;
|
|
27
31
|
}
|
|
28
32
|
|
|
@@ -33,7 +37,7 @@ export function createLazySessionStorage(): LazySessionStorage {
|
|
|
33
37
|
sessionStorage.removeItem(key);
|
|
34
38
|
|
|
35
39
|
entries.push({
|
|
36
|
-
key: key.slice(
|
|
40
|
+
key: key.slice(sessionStoragePrefix.length),
|
|
37
41
|
value
|
|
38
42
|
});
|
|
39
43
|
}
|
|
@@ -74,7 +78,7 @@ export function createLazySessionStorage(): LazySessionStorage {
|
|
|
74
78
|
return;
|
|
75
79
|
}
|
|
76
80
|
|
|
77
|
-
sessionStorage.removeItem(
|
|
81
|
+
sessionStorage.removeItem(getSessionStorageKey(entry.key));
|
|
78
82
|
|
|
79
83
|
const index = entries.indexOf(entry);
|
|
80
84
|
|
|
@@ -96,7 +100,7 @@ export function createLazySessionStorage(): LazySessionStorage {
|
|
|
96
100
|
},
|
|
97
101
|
setItem: (key, value) => {
|
|
98
102
|
if (isPersistenceEnabled) {
|
|
99
|
-
sessionStorage.setItem(
|
|
103
|
+
sessionStorage.setItem(getSessionStorageKey(key), value);
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
update: {
|
|
@@ -44,6 +44,11 @@ export function parseKeycloakIssuerUri(issuerUri: string):
|
|
|
44
44
|
kcHttpRelativePath: keycloakUtils.issuerUriParsed.kcHttpRelativePath,
|
|
45
45
|
adminConsoleUrl: keycloakUtils.adminConsoleUrl,
|
|
46
46
|
adminConsoleUrl_master: keycloakUtils.adminConsoleUrl_master,
|
|
47
|
-
getAccountUrl:
|
|
47
|
+
getAccountUrl: ({ clientId, backToAppFromAccountUrl, locale }) =>
|
|
48
|
+
keycloakUtils.getAccountUrl({
|
|
49
|
+
clientId,
|
|
50
|
+
validRedirectUri: backToAppFromAccountUrl,
|
|
51
|
+
locale
|
|
52
|
+
})
|
|
48
53
|
};
|
|
49
54
|
}
|
|
@@ -7,4 +7,6 @@ export type LazySessionStorage = {
|
|
|
7
7
|
setItem(key: string, value: string): void;
|
|
8
8
|
persistCurrentStateAndSubsequentChanges: () => void;
|
|
9
9
|
};
|
|
10
|
-
export declare function createLazySessionStorage(
|
|
10
|
+
export declare function createLazySessionStorage(params: {
|
|
11
|
+
storageId: string;
|
|
12
|
+
}): LazySessionStorage;
|
|
@@ -2,20 +2,22 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createLazySessionStorage = createLazySessionStorage;
|
|
4
4
|
const assert_1 = require("../tools/tsafe/assert");
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
function createLazySessionStorage(params) {
|
|
6
|
+
const { storageId } = params;
|
|
7
|
+
const sessionStoragePrefix = `lazy-session-storage:${storageId}:`;
|
|
8
|
+
const getSessionStorageKey = (key) => `${sessionStoragePrefix}${key}`;
|
|
7
9
|
const entries = [];
|
|
8
10
|
for (let i = 0; i < sessionStorage.length; i++) {
|
|
9
11
|
const key = sessionStorage.key(i);
|
|
10
12
|
(0, assert_1.assert)(key !== null, "470498");
|
|
11
|
-
if (!key.startsWith(
|
|
13
|
+
if (!key.startsWith(sessionStoragePrefix)) {
|
|
12
14
|
continue;
|
|
13
15
|
}
|
|
14
16
|
const value = sessionStorage.getItem(key);
|
|
15
17
|
(0, assert_1.assert)(value !== null, "846771");
|
|
16
18
|
sessionStorage.removeItem(key);
|
|
17
19
|
entries.push({
|
|
18
|
-
key: key.slice(
|
|
20
|
+
key: key.slice(sessionStoragePrefix.length),
|
|
19
21
|
value
|
|
20
22
|
});
|
|
21
23
|
}
|
|
@@ -46,7 +48,7 @@ function createLazySessionStorage() {
|
|
|
46
48
|
if (entry === undefined) {
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
|
-
sessionStorage.removeItem(
|
|
51
|
+
sessionStorage.removeItem(getSessionStorageKey(entry.key));
|
|
50
52
|
const index = entries.indexOf(entry);
|
|
51
53
|
entries.splice(index, 1);
|
|
52
54
|
},
|
|
@@ -66,7 +68,7 @@ function createLazySessionStorage() {
|
|
|
66
68
|
},
|
|
67
69
|
setItem: (key, value) => {
|
|
68
70
|
if (isPersistenceEnabled) {
|
|
69
|
-
sessionStorage.setItem(
|
|
71
|
+
sessionStorage.setItem(getSessionStorageKey(key), value);
|
|
70
72
|
}
|
|
71
73
|
update: {
|
|
72
74
|
const entry = entries.find(entry => entry.key === key);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazySessionStorage.js","sourceRoot":"","sources":["../src/tools/lazySessionStorage.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"lazySessionStorage.js","sourceRoot":"","sources":["../src/tools/lazySessionStorage.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,7 +30,11 @@ function parseKeycloakIssuerUri(issuerUri) {
|
|
|
30
30
|
kcHttpRelativePath: keycloakUtils.issuerUriParsed.kcHttpRelativePath,
|
|
31
31
|
adminConsoleUrl: keycloakUtils.adminConsoleUrl,
|
|
32
32
|
adminConsoleUrl_master: keycloakUtils.adminConsoleUrl_master,
|
|
33
|
-
getAccountUrl: keycloakUtils.getAccountUrl
|
|
33
|
+
getAccountUrl: ({ clientId, backToAppFromAccountUrl, locale }) => keycloakUtils.getAccountUrl({
|
|
34
|
+
clientId,
|
|
35
|
+
validRedirectUri: backToAppFromAccountUrl,
|
|
36
|
+
locale
|
|
37
|
+
})
|
|
34
38
|
};
|
|
35
39
|
}
|
|
36
40
|
//# sourceMappingURL=parseKeycloakIssuerUri.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseKeycloakIssuerUri.js","sourceRoot":"","sources":["../src/tools/parseKeycloakIssuerUri.ts"],"names":[],"mappings":";;AAmBA,
|
|
1
|
+
{"version":3,"file":"parseKeycloakIssuerUri.js","sourceRoot":"","sources":["../src/tools/parseKeycloakIssuerUri.ts"],"names":[],"mappings":";;AAmBA,wDAkCC;AArDD,0CAA8D;AAE9D;;;;;;;;;;;;;;;;KAgBK;AACL,SAAgB,sBAAsB,CAAC,SAAiB;IAepD,IAAI,CAAC,IAAA,qBAAU,EAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,MAAM,aAAa,GAAG,IAAA,8BAAmB,EAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IAEzD,OAAO;QACH,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,MAAM;QAC5C,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,KAAK;QAC1C,kBAAkB,EAAE,aAAa,CAAC,eAAe,CAAC,kBAAkB;QACpE,eAAe,EAAE,aAAa,CAAC,eAAe;QAC9C,sBAAsB,EAAE,aAAa,CAAC,sBAAsB;QAC5D,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,EAAE,EAAE,EAAE,CAC7D,aAAa,CAAC,aAAa,CAAC;YACxB,QAAQ;YACR,gBAAgB,EAAE,uBAAuB;YACzC,MAAM;SACT,CAAC;KACT,CAAC;AACN,CAAC"}
|
|
@@ -59,7 +59,8 @@ function manageOptimizedDeps(params) {
|
|
|
59
59
|
const moduleNames_include = [
|
|
60
60
|
"oidc-spa/react-spa",
|
|
61
61
|
"oidc-spa/entrypoint",
|
|
62
|
-
"oidc-spa/keycloak"
|
|
62
|
+
"oidc-spa/keycloak",
|
|
63
|
+
"oidc-spa/core"
|
|
63
64
|
];
|
|
64
65
|
for (const moduleName of moduleNames_include) {
|
|
65
66
|
(0, assert_1.assert)(moduleNames.includes(moduleName));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manageOptimizedDeps.js","sourceRoot":"","sources":["../src/vite-plugin/manageOptimizedDeps.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,
|
|
1
|
+
{"version":3,"file":"manageOptimizedDeps.js","sourceRoot":"","sources":["../src/vite-plugin/manageOptimizedDeps.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,kDA2DC;AAjED,4FAAqF;AACrF,4CAA8B;AAC9B,+BAAwC;AAExC,kDAA+C;AAE/C,SAAgB,mBAAmB,CAAC,MAGnC;;IACG,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAE3C,IAAI,WAAW,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO,UAAU,CAAC;IACtB,CAAC;IAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAChC,EAAE,CAAC,YAAY,CAAC,IAAA,WAAQ,EAAC,IAAA,2DAA0B,GAAE,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CACzB,CAAC;IAEpE,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC;SACxD,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC;SACjD,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhE,QAAQ,WAAW,EAAE,CAAC;QAClB,KAAK,gBAAgB;YACjB,CAAC;gBACG,OAAC,CAAC,UAAU,CAAC,YAAY,KAAvB,UAAU,CAAC,YAAY,GAAK,EAAE,EAAC,EAAC,OAAO,QAAP,OAAO,GAAK,EAAE,EAAC,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;YAC3E,CAAC;YACD,MAAM;QACV,KAAK,wBAAwB;YACzB,CAAC;gBACG,MAAM,mBAAmB,GAAG;oBACxB,oBAAoB;oBACpB,qBAAqB;oBACrB,mBAAmB;oBACnB,eAAe;iBAClB,CAAC;gBAEF,KAAK,MAAM,UAAU,IAAI,mBAAmB,EAAE,CAAC;oBAC3C,IAAA,eAAM,EAAC,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;gBAC7C,CAAC;gBAED,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE;oBACzB,IAAI,CAAC;wBACD,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;oBACxC,CAAC;oBAAC,MAAM,CAAC;wBACL,OAAO,KAAK,CAAC;oBACjB,CAAC;oBAED,OAAO,IAAI,CAAC;gBAChB,CAAC,CAAC,EAAE,CAAC;gBAEL,IAAI,cAAc,EAAE,CAAC;oBACjB,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpC,CAAC;gBAED,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAErC,OAAC,CAAC,UAAU,CAAC,YAAY,KAAvB,UAAU,CAAC,YAAY,GAAK,EAAE,EAAC,EAAC,OAAO,QAAP,OAAO,GAAK,EAAE,EAAC,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,CAAC;YACnF,CAAC;YACD,MAAM;IACd,CAAC;IAED,OAAO,UAAU,CAAC;AACtB,CAAC"}
|