oidc-spa 8.1.15 → 8.2.1

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.
Files changed (151) hide show
  1. package/core/BASE_URL.d.ts +4 -0
  2. package/core/BASE_URL.js +12 -0
  3. package/core/BASE_URL.js.map +1 -0
  4. package/core/OidcMetadata.d.ts +5 -0
  5. package/core/OidcMetadata.js +56 -0
  6. package/core/OidcMetadata.js.map +1 -1
  7. package/core/createOidc.d.ts +15 -8
  8. package/core/createOidc.js +207 -104
  9. package/core/createOidc.js.map +1 -1
  10. package/core/diagnostic.d.ts +0 -1
  11. package/core/diagnostic.js +18 -5
  12. package/core/diagnostic.js.map +1 -1
  13. package/core/earlyInit.d.ts +1 -0
  14. package/core/earlyInit.js +8 -8
  15. package/core/earlyInit.js.map +1 -1
  16. package/core/loginOrGoToAuthServer.d.ts +0 -1
  17. package/core/loginOrGoToAuthServer.js +1 -16
  18. package/core/loginOrGoToAuthServer.js.map +1 -1
  19. package/core/loginSilent.d.ts +1 -2
  20. package/core/loginSilent.js +3 -21
  21. package/core/loginSilent.js.map +1 -1
  22. package/core/prShouldLoadApp.d.ts +4 -0
  23. package/core/prShouldLoadApp.js +13 -0
  24. package/core/prShouldLoadApp.js.map +1 -0
  25. package/esm/core/BASE_URL.d.ts +4 -0
  26. package/esm/core/BASE_URL.js +8 -0
  27. package/esm/core/BASE_URL.js.map +1 -0
  28. package/esm/core/OidcMetadata.d.ts +5 -0
  29. package/esm/core/OidcMetadata.js +54 -0
  30. package/esm/core/OidcMetadata.js.map +1 -1
  31. package/esm/core/createOidc.d.ts +15 -8
  32. package/esm/core/createOidc.js +207 -104
  33. package/esm/core/createOidc.js.map +1 -1
  34. package/esm/core/diagnostic.d.ts +0 -1
  35. package/esm/core/diagnostic.js +15 -1
  36. package/esm/core/diagnostic.js.map +1 -1
  37. package/esm/core/earlyInit.d.ts +1 -0
  38. package/esm/core/earlyInit.js +8 -8
  39. package/esm/core/earlyInit.js.map +1 -1
  40. package/esm/core/loginOrGoToAuthServer.d.ts +0 -1
  41. package/esm/core/loginOrGoToAuthServer.js +1 -16
  42. package/esm/core/loginOrGoToAuthServer.js.map +1 -1
  43. package/esm/core/loginSilent.d.ts +1 -2
  44. package/esm/core/loginSilent.js +3 -21
  45. package/esm/core/loginSilent.js.map +1 -1
  46. package/esm/core/prShouldLoadApp.d.ts +4 -0
  47. package/esm/core/prShouldLoadApp.js +9 -0
  48. package/esm/core/prShouldLoadApp.js.map +1 -0
  49. package/esm/keycloak/keycloak-js/Keycloak.d.ts +1 -1
  50. package/esm/keycloak/keycloak-js/Keycloak.js +1 -1
  51. package/esm/keycloak/keycloak-js/Keycloak.js.map +1 -1
  52. package/esm/keycloak/keycloakIssuerUriParsed.js +8 -1
  53. package/esm/keycloak/keycloakIssuerUriParsed.js.map +1 -1
  54. package/esm/mock/oidc.d.ts +3 -1
  55. package/esm/mock/oidc.js +4 -2
  56. package/esm/mock/oidc.js.map +1 -1
  57. package/esm/react-spa/apiBuilder.d.ts +12 -0
  58. package/esm/react-spa/apiBuilder.js +26 -0
  59. package/esm/react-spa/apiBuilder.js.map +1 -0
  60. package/esm/react-spa/createOidcSpaApi.d.ts +8 -0
  61. package/esm/react-spa/createOidcSpaApi.js +387 -0
  62. package/esm/react-spa/createOidcSpaApi.js.map +1 -0
  63. package/esm/react-spa/index.d.ts +2 -0
  64. package/esm/react-spa/index.js +3 -0
  65. package/esm/react-spa/index.js.map +1 -0
  66. package/esm/react-spa/types.d.ts +279 -0
  67. package/esm/react-spa/types.js +2 -0
  68. package/esm/react-spa/types.js.map +1 -0
  69. package/esm/tanstack-start/react/apiBuilder.js.map +1 -1
  70. package/esm/tanstack-start/react/createOidcSpaApi.js +13 -9
  71. package/esm/tanstack-start/react/createOidcSpaApi.js.map +1 -1
  72. package/esm/tanstack-start/react/types.d.ts +5 -4
  73. package/esm/tools/isLikelyDevServer.d.ts +1 -0
  74. package/esm/tools/isLikelyDevServer.js +14 -0
  75. package/esm/tools/isLikelyDevServer.js.map +1 -0
  76. package/keycloak/keycloak-js/Keycloak.d.ts +1 -1
  77. package/keycloak/keycloak-js/Keycloak.js +1 -1
  78. package/keycloak/keycloak-js/Keycloak.js.map +1 -1
  79. package/keycloak/keycloakIssuerUriParsed.js +8 -1
  80. package/keycloak/keycloakIssuerUriParsed.js.map +1 -1
  81. package/mock/oidc.d.ts +3 -1
  82. package/mock/oidc.js +4 -2
  83. package/mock/oidc.js.map +1 -1
  84. package/package.json +5 -1
  85. package/react-spa/apiBuilder.d.ts +12 -0
  86. package/react-spa/apiBuilder.js +29 -0
  87. package/react-spa/apiBuilder.js.map +1 -0
  88. package/react-spa/createOidcSpaApi.d.ts +8 -0
  89. package/react-spa/createOidcSpaApi.js +423 -0
  90. package/react-spa/createOidcSpaApi.js.map +1 -0
  91. package/react-spa/index.d.ts +2 -0
  92. package/react-spa/index.js +6 -0
  93. package/react-spa/index.js.map +1 -0
  94. package/react-spa/types.d.ts +279 -0
  95. package/react-spa/types.js +3 -0
  96. package/react-spa/types.js.map +1 -0
  97. package/src/angular.ts +1 -1
  98. package/src/core/BASE_URL.ts +9 -0
  99. package/src/core/OidcMetadata.ts +75 -0
  100. package/src/core/createOidc.ts +273 -147
  101. package/src/core/diagnostic.ts +21 -2
  102. package/src/core/earlyInit.ts +14 -11
  103. package/src/core/loginOrGoToAuthServer.ts +0 -22
  104. package/src/core/loginSilent.ts +4 -27
  105. package/src/core/prShouldLoadApp.ts +11 -0
  106. package/src/keycloak/keycloak-js/Keycloak.ts +2 -2
  107. package/src/keycloak/keycloakIssuerUriParsed.ts +10 -1
  108. package/src/mock/oidc.ts +9 -3
  109. package/src/react-spa/apiBuilder.ts +70 -0
  110. package/src/react-spa/createOidcSpaApi.tsx +527 -0
  111. package/src/react-spa/index.ts +4 -0
  112. package/src/react-spa/types.tsx +308 -0
  113. package/src/tanstack-start/react/apiBuilder.ts +0 -1
  114. package/src/tanstack-start/react/createOidcSpaApi.tsx +24 -20
  115. package/src/tanstack-start/react/types.tsx +3 -4
  116. package/src/tools/isLikelyDevServer.ts +17 -0
  117. package/src/vite-plugin/handleClientEntrypoint.ts +5 -5
  118. package/src/vite-plugin/manageOptimizedDeps.ts +64 -0
  119. package/src/vite-plugin/projectType.ts +18 -0
  120. package/src/vite-plugin/vite-plugin.ts +40 -10
  121. package/tools/isLikelyDevServer.d.ts +1 -0
  122. package/tools/isLikelyDevServer.js +17 -0
  123. package/tools/isLikelyDevServer.js.map +1 -0
  124. package/vite-plugin/handleClientEntrypoint.d.ts +2 -0
  125. package/vite-plugin/handleClientEntrypoint.js +3 -4
  126. package/vite-plugin/handleClientEntrypoint.js.map +1 -1
  127. package/vite-plugin/manageOptimizedDeps.d.ts +6 -0
  128. package/vite-plugin/{excludeModuleExportFromOptimizedDeps.js → manageOptimizedDeps.js} +42 -7
  129. package/vite-plugin/manageOptimizedDeps.js.map +1 -0
  130. package/vite-plugin/projectType.d.ts +4 -0
  131. package/vite-plugin/projectType.js +15 -0
  132. package/vite-plugin/projectType.js.map +1 -0
  133. package/vite-plugin/{transformCreateFileRoute.js → transformTanstackRouterCreateFileRoute.js} +1 -1
  134. package/vite-plugin/transformTanstackRouterCreateFileRoute.js.map +1 -0
  135. package/vite-plugin/vite-plugin.d.ts +1 -1
  136. package/vite-plugin/vite-plugin.js +28 -8
  137. package/vite-plugin/vite-plugin.js.map +1 -1
  138. package/esm/tools/infer_import_meta_env_BASE_URL.d.ts +0 -1
  139. package/esm/tools/infer_import_meta_env_BASE_URL.js +0 -15
  140. package/esm/tools/infer_import_meta_env_BASE_URL.js.map +0 -1
  141. package/src/tools/infer_import_meta_env_BASE_URL.ts +0 -19
  142. package/src/vite-plugin/detectProjectType.ts +0 -20
  143. package/src/vite-plugin/excludeModuleExportFromOptimizedDeps.ts +0 -20
  144. package/vite-plugin/detectProjectType.d.ts +0 -10
  145. package/vite-plugin/detectProjectType.js +0 -15
  146. package/vite-plugin/detectProjectType.js.map +0 -1
  147. package/vite-plugin/excludeModuleExportFromOptimizedDeps.d.ts +0 -4
  148. package/vite-plugin/excludeModuleExportFromOptimizedDeps.js.map +0 -1
  149. package/vite-plugin/transformCreateFileRoute.js.map +0 -1
  150. /package/src/vite-plugin/{transformCreateFileRoute.ts → transformTanstackRouterCreateFileRoute.ts} +0 -0
  151. /package/vite-plugin/{transformCreateFileRoute.d.ts → transformTanstackRouterCreateFileRoute.d.ts} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  type User as OidcClientTsUser,
5
5
  InMemoryWebStorage
6
6
  } from "../vendor/frontend/oidc-client-ts";
7
- import type { OidcMetadata } from "./OidcMetadata";
7
+ import { type OidcMetadata, fetchOidcMetadata } from "./OidcMetadata";
8
8
  import { assert, is, type Equals } from "../tools/tsafe/assert";
9
9
  import { id } from "../tools/tsafe/id";
10
10
  import { setTimeout, clearTimeout } from "../tools/workerTimers";
@@ -49,8 +49,10 @@ import { createGetIsNewBrowserSession } from "./isNewBrowserSession";
49
49
  import { getIsOnline } from "../tools/getIsOnline";
50
50
  import { isKeycloak } from "../keycloak/isKeycloak";
51
51
  import { INFINITY_TIME } from "../tools/INFINITY_TIME";
52
- import type { WELL_KNOWN_PATH } from "./diagnostic";
53
- import { getIsValidRemoteJson } from "../tools/getIsValidRemoteJson";
52
+ import { prShouldLoadApp } from "./prShouldLoadApp";
53
+ import { getBASE_URL } from "./BASE_URL";
54
+ import { getIsLikelyDevServer } from "../tools/isLikelyDevServer";
55
+ import { createObjectThatThrowsIfAccessed } from "../tools/createObjectThatThrowsIfAccessed";
54
56
 
55
57
  // NOTE: Replaced at build time
56
58
  const VERSION = "{{OIDC_SPA_VERSION}}";
@@ -59,14 +61,6 @@ export type ParamsOfCreateOidc<
59
61
  DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_OidcCoreSpec,
60
62
  AutoLogin extends boolean = false
61
63
  > = {
62
- /**
63
- * What should you put in this parameter?
64
- * - Vite project: `BASE_URL: import.meta.env.BASE_URL`
65
- * - Create React App project: `BASE_URL: process.env.PUBLIC_URL`
66
- * - Other: `BASE_URL: "/"` (Usually, or `/dashboard` if your app is not at the root of the domain)
67
- */
68
- homeUrl: string;
69
-
70
64
  /**
71
65
  * See: https://docs.oidc-spa.dev/v/v8/providers-configuration/provider-configuration
72
66
  */
@@ -194,6 +188,22 @@ export type ParamsOfCreateOidc<
194
188
  * or non-standard deployments), and you cannot fix the server-side configuration.
195
189
  */
196
190
  __metadata?: Partial<OidcMetadata>;
191
+
192
+ /**
193
+ * NOTE: This parameter is optional if you use the Vite plugin.
194
+ *
195
+ * This parameter let's you overwrite the value provided in
196
+ * oidcEarlyInit({ BASE_URL: xxx });
197
+ *
198
+ * What should you put in this parameter?
199
+ * - Vite project: `BASE_URL: import.meta.env.BASE_URL`
200
+ * - Create React App project: `BASE_URL: process.env.PUBLIC_URL`
201
+ * - Other: `BASE_URL: "/"` (Usually, or `/dashboard` if your app is not at the root of the domain)
202
+ */
203
+ BASE_URL?: string;
204
+
205
+ /** @deprecated: Use BASE_URL (same thing, just renamed). */
206
+ homeUrl?: string;
197
207
  };
198
208
 
199
209
  const globalContext = {
@@ -314,11 +324,31 @@ export async function createOidc_nonMemoized<
314
324
  log: typeof console.log | undefined;
315
325
  }
316
326
  ): Promise<AutoLogin extends true ? Oidc.LoggedIn<DecodedIdToken> : Oidc<DecodedIdToken>> {
327
+ {
328
+ const timer = window.setTimeout(() => {
329
+ console.warn(
330
+ [
331
+ "oidc-spa: Setup error.",
332
+ "oidcEarlyInit() wasn't called.",
333
+ "This is supposed to be handled by the oidc-spa Vite plugin",
334
+ "or manually in other environments."
335
+ ].join(" ")
336
+ );
337
+ }, 3_000);
338
+
339
+ const shouldLoadApp = await prShouldLoadApp;
340
+
341
+ window.clearTimeout(timer);
342
+
343
+ if (!shouldLoadApp) {
344
+ return new Promise<never>(() => {});
345
+ }
346
+ }
347
+
317
348
  const {
318
349
  transformUrlBeforeRedirect,
319
350
  extraQueryParams: extraQueryParamsOrGetter,
320
351
  extraTokenParams: extraTokenParamsOrGetter,
321
- homeUrl: homeUrl_params,
322
352
  decodedIdTokenSchema,
323
353
  idleSessionLifetimeInSeconds,
324
354
  autoLogoutParams = { redirectTo: "current page" },
@@ -330,6 +360,8 @@ export async function createOidc_nonMemoized<
330
360
  noIframe = false
331
361
  } = params;
332
362
 
363
+ const BASE_URL_params = params.BASE_URL ?? params.homeUrl;
364
+
333
365
  const { issuerUri, clientId, scopes, configId, log } = preProcessedParams;
334
366
 
335
367
  const getExtraQueryParams = (() => {
@@ -357,7 +389,29 @@ export async function createOidc_nonMemoized<
357
389
  })();
358
390
 
359
391
  const homeUrlAndRedirectUri = toFullyQualifiedUrl({
360
- urlish: homeUrl_params,
392
+ urlish: (() => {
393
+ if (BASE_URL_params !== undefined) {
394
+ return BASE_URL_params;
395
+ }
396
+
397
+ const BASE_URL = getBASE_URL();
398
+
399
+ if (BASE_URL === undefined) {
400
+ throw new Error(
401
+ [
402
+ "oidc-spa: If you do not use the oidc-spa Vite plugin",
403
+ "you must provide the BASE_URL to the earlyInit() examples:",
404
+ "oidcSpaEarlyInit({ BASE_URL: import.meta.env.BASE_URL })",
405
+ "oidcSpaEarlyInit({ BASE_URL: '/' })",
406
+ "",
407
+ "You can also pass this parameter to createOidc({ BASE_URL: '...' })",
408
+ "or bootstrapOidc({ BASE_URL: '...' })"
409
+ ].join("\n")
410
+ );
411
+ }
412
+
413
+ return BASE_URL;
414
+ })(),
361
415
  doAssertNoQueryParams: true,
362
416
  doOutputWithTrailingSlash: true
363
417
  });
@@ -378,92 +432,212 @@ export async function createOidc_nonMemoized<
378
432
 
379
433
  const stateUrlParamValue_instance = generateStateUrlParamValue();
380
434
 
435
+ const oidcMetadata = __metadata ?? (await fetchOidcMetadata({ issuerUri }));
436
+
381
437
  const canUseIframe = (() => {
382
438
  if (noIframe) {
383
439
  return false;
384
440
  }
385
441
 
386
442
  third_party_cookies: {
387
- const isOidcServerThirdPartyRelativeToApp =
388
- getHaveSharedParentDomain({
389
- url1: window.location.origin,
390
- url2: issuerUri
391
- }) === false;
392
-
393
- if (!isOidcServerThirdPartyRelativeToApp) {
394
- break third_party_cookies;
443
+ if (oidcMetadata === undefined) {
444
+ return false;
395
445
  }
396
446
 
397
- const isGoogleChrome = (() => {
398
- const ua = navigator.userAgent;
399
- const vendor = navigator.vendor;
447
+ const { authorization_endpoint } = oidcMetadata;
400
448
 
401
- return (
402
- /Chrome/.test(ua) && /Google Inc/.test(vendor) && !/Edg/.test(ua) && !/OPR/.test(ua)
403
- );
404
- })();
449
+ assert(
450
+ authorization_endpoint !== undefined,
451
+ "Missing authorization_endpoint on the provided __metadata"
452
+ );
453
+
454
+ const isOidcServerThirdPartyRelativeToApp = !getHaveSharedParentDomain({
455
+ url1: window.location.origin,
456
+ // TODO: No, here we should test against the authorization endpoint!
457
+ url2: authorization_endpoint
458
+ });
405
459
 
406
- if (window.location.origin.startsWith("http://localhost") && isGoogleChrome) {
460
+ if (!isOidcServerThirdPartyRelativeToApp) {
407
461
  break third_party_cookies;
408
462
  }
409
463
 
410
- log?.(
411
- [
412
- "Can't use iframe because your auth server is on a third party domain relative",
413
- "to the domain of your app and third party cookies are blocked by navigators."
414
- ].join(" ")
415
- );
464
+ const isLikelyDevServer = getIsLikelyDevServer();
416
465
 
417
- return false;
418
- }
466
+ const domain_auth = new URL(authorization_endpoint).origin.split("//")[1];
419
467
 
420
- // NOTE: Maybe not, it depend if the app can iframe itself.
421
- return true;
422
- })();
468
+ assert(domain_auth !== undefined, "33921384");
469
+
470
+ const domain_here = window.location.origin.split("//")[1];
471
+
472
+ let isWellKnownProviderDomain = false;
473
+ let isIp = false;
423
474
 
424
- let isUserStoreInMemoryOnly: boolean;
425
-
426
- const oidcClientTsUserManager = new OidcClientTsUserManager({
427
- stateUrlParamValue: stateUrlParamValue_instance,
428
- authority: issuerUri,
429
- client_id: clientId,
430
- redirect_uri: homeUrlAndRedirectUri,
431
- silent_redirect_uri: homeUrlAndRedirectUri,
432
- post_logout_redirect_uri: homeUrlAndRedirectUri,
433
- response_mode: isKeycloak({ issuerUri }) ? "fragment" : "query",
434
- response_type: "code",
435
- scope: Array.from(new Set(["openid", ...scopes])).join(" "),
436
- automaticSilentRenew: false,
437
- userStore: new WebStorageStateStore({
438
- store: (() => {
439
- if (canUseIframe) {
440
- isUserStoreInMemoryOnly = true;
441
- return new InMemoryWebStorage();
475
+ const suggestedDeployments = (() => {
476
+ if (/^(?:\d{1,3}\.){3}\d{1,3}$|^\[?[A-Fa-f0-9:]+\]?$/.test(domain_auth)) {
477
+ isIp = true;
478
+ return [];
442
479
  }
443
480
 
444
- isUserStoreInMemoryOnly = false;
481
+ const baseDomain = (() => {
482
+ const segments = domain_auth.split(".");
445
483
 
446
- const storage = createEphemeralSessionStorage({
447
- sessionStorageTtlMs: 3 * 60_000
448
- });
484
+ if (segments.length >= 3) {
485
+ segments.shift();
486
+ }
487
+ return segments.join(".");
488
+ })();
449
489
 
450
- const { evtRequestToPersistTokens } = globalContext;
490
+ {
491
+ const baseDomain_low = baseDomain.toLowerCase();
451
492
 
452
- evtRequestToPersistTokens.subscribe(({ configIdOfInstancePostingTheRequest }) => {
453
- if (configIdOfInstancePostingTheRequest === configId) {
454
- return;
493
+ if (
494
+ baseDomain_low.includes("auth0") ||
495
+ baseDomain_low.includes("clerk") ||
496
+ baseDomain_low.includes("microsoft") ||
497
+ baseDomain_low.includes("okta") ||
498
+ baseDomain_low.includes("aws")
499
+ ) {
500
+ isWellKnownProviderDomain = true;
501
+ return [];
455
502
  }
503
+ }
456
504
 
457
- storage.persistCurrentStateAndSubsequentChanges();
458
- });
505
+ const baseUrl = new URL(homeUrlAndRedirectUri).pathname;
459
506
 
460
- return storage;
461
- })()
462
- }),
463
- stateStore: new WebStorageStateStore({ store: localStorage, prefix: STATE_STORE_KEY_PREFIX }),
464
- client_secret: __unsafe_clientSecret,
465
- metadata: __metadata
466
- });
507
+ return [
508
+ `myapp.${baseDomain}`,
509
+ baseDomain === domain_auth ? undefined : baseDomain,
510
+ `${baseDomain}/${baseUrl === "/" ? "dashboard" : baseUrl}`
511
+ ].filter(x => x !== undefined);
512
+ })();
513
+
514
+ if (isLikelyDevServer) {
515
+ log?.(
516
+ [
517
+ "Detected localhost environment.",
518
+ "\nWhen reloading while logged in, you may briefly see",
519
+ "some URL params appear in the address bar.",
520
+ "\nThis happens because session restore via iframe is disabled,",
521
+ "the browser treats your auth server as a third party.",
522
+ `\nAuth server: ${domain_auth}`,
523
+ `\nApp domain: ${domain_here}`,
524
+ ...(() => {
525
+ if (isIp) {
526
+ return [];
527
+ }
528
+
529
+ if (isWellKnownProviderDomain) {
530
+ return [
531
+ "\nYou seem to be using a well-known auth provider.",
532
+ "Check your provider's docs, some allow configuring",
533
+ `a your custom domain at least for the authorization endpoint.`,
534
+ "\nIf configured, oidc-spa will restore sessions silently",
535
+ "and improve the user experience."
536
+ ];
537
+ }
538
+
539
+ return [
540
+ "\nOnce deployed under the same root domain as your auth server,",
541
+ "oidc-spa will use iframes to restore sessions silently.",
542
+ "\nSuggested deployments:",
543
+ ...suggestedDeployments.map(d => `\n • ${d}`)
544
+ ];
545
+ })(),
546
+ "\n\nMore info:",
547
+ "https://docs.oidc-spa.dev/v/v8/resources/end-of-third-party-cookies#when-are-cookies-considered-third-party"
548
+ ].join(" ")
549
+ );
550
+ } else {
551
+ log?.(
552
+ [
553
+ "Silent session restore via iframe is disabled.",
554
+ `\nAuth server: ${domain_auth}`,
555
+ `App domain: ${domain_here}`,
556
+ "\nThey do not share a common root domain.",
557
+ ...(() => {
558
+ if (isIp) {
559
+ return [];
560
+ }
561
+
562
+ if (isWellKnownProviderDomain) {
563
+ return [
564
+ "\nYou seem to be using a well-known auth provider.",
565
+ "Check if you can configure a custom auth domain.",
566
+ "\nIf so, oidc-spa can restore sessions silently",
567
+ "and improve the user experience."
568
+ ];
569
+ }
570
+
571
+ return [
572
+ "\nTo improve the experience, here are some examples of deployment for your app:",
573
+ ...suggestedDeployments.map(d => `\n • ${d}`)
574
+ ];
575
+ })(),
576
+ "\nMore info:",
577
+ "https://docs.oidc-spa.dev/v/v8/resources/end-of-third-party-cookies#when-are-cookies-considered-third-party"
578
+ ].join(" ")
579
+ );
580
+ }
581
+
582
+ return false;
583
+ }
584
+
585
+ return true;
586
+ })();
587
+
588
+ let isUserStoreInMemoryOnly: boolean | undefined = undefined;
589
+
590
+ const oidcClientTsUserManager =
591
+ oidcMetadata === undefined
592
+ ? createObjectThatThrowsIfAccessed<OidcClientTsUserManager>({
593
+ debugMessage: "oidc-spa: Wrong assertion 43943"
594
+ })
595
+ : new OidcClientTsUserManager({
596
+ stateUrlParamValue: stateUrlParamValue_instance,
597
+ authority: issuerUri,
598
+ client_id: clientId,
599
+ redirect_uri: homeUrlAndRedirectUri,
600
+ silent_redirect_uri: homeUrlAndRedirectUri,
601
+ post_logout_redirect_uri: homeUrlAndRedirectUri,
602
+ response_mode: isKeycloak({ issuerUri }) ? "fragment" : "query",
603
+ response_type: "code",
604
+ scope: Array.from(new Set(["openid", ...scopes])).join(" "),
605
+ automaticSilentRenew: false,
606
+ userStore: new WebStorageStateStore({
607
+ store: (() => {
608
+ if (canUseIframe) {
609
+ isUserStoreInMemoryOnly = true;
610
+ return new InMemoryWebStorage();
611
+ }
612
+
613
+ isUserStoreInMemoryOnly = false;
614
+
615
+ const storage = createEphemeralSessionStorage({
616
+ sessionStorageTtlMs: 3 * 60_000
617
+ });
618
+
619
+ const { evtRequestToPersistTokens } = globalContext;
620
+
621
+ evtRequestToPersistTokens.subscribe(
622
+ ({ configIdOfInstancePostingTheRequest }) => {
623
+ if (configIdOfInstancePostingTheRequest === configId) {
624
+ return;
625
+ }
626
+
627
+ storage.persistCurrentStateAndSubsequentChanges();
628
+ }
629
+ );
630
+
631
+ return storage;
632
+ })()
633
+ }),
634
+ stateStore: new WebStorageStateStore({
635
+ store: localStorage,
636
+ prefix: STATE_STORE_KEY_PREFIX
637
+ }),
638
+ client_secret: __unsafe_clientSecret,
639
+ metadata: oidcMetadata
640
+ });
467
641
 
468
642
  const evtInitializationOutcomeUserNotLoggedIn = createEvt<void>();
469
643
 
@@ -493,6 +667,14 @@ export async function createOidc_nonMemoized<
493
667
  backFromAuthServer: Oidc.LoggedIn["backFromAuthServer"]; // Undefined is silent signin
494
668
  }
495
669
  > => {
670
+ if (oidcMetadata === undefined) {
671
+ return (
672
+ await import("./diagnostic")
673
+ ).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
674
+ issuerUri
675
+ });
676
+ }
677
+
496
678
  handle_redirect_auth_response: {
497
679
  let stateDataAndAuthResponse:
498
680
  | { stateData: StateData.Redirect; authResponse: AuthResponse }
@@ -677,6 +859,8 @@ export async function createOidc_nonMemoized<
677
859
  // NOTE: We almost never persist tokens, we have to only to support edge case
678
860
  // of multiple oidc instance in a single App with no iframe support.
679
861
  restore_from_session_storage: {
862
+ assert(isUserStoreInMemoryOnly !== undefined, "3392204");
863
+
680
864
  if (isUserStoreInMemoryOnly) {
681
865
  break restore_from_session_storage;
682
866
  }
@@ -747,20 +931,6 @@ export async function createOidc_nonMemoized<
747
931
  }
748
932
 
749
933
  if (!canUseIframe) {
750
- if (
751
- !(await getIsValidRemoteJson(
752
- `${issuerUri}${id<typeof WELL_KNOWN_PATH>(
753
- "/.well-known/openid-configuration"
754
- )}`
755
- ))
756
- ) {
757
- return (
758
- await import("./diagnostic")
759
- ).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
760
- issuerUri
761
- });
762
- }
763
-
764
934
  break actual_silent_signin;
765
935
  }
766
936
 
@@ -781,26 +951,13 @@ export async function createOidc_nonMemoized<
781
951
 
782
952
  assert(result_loginSilent.outcome !== "token refreshed using refresh token", "876995");
783
953
 
784
- if (result_loginSilent.outcome === "failure") {
785
- switch (result_loginSilent.cause) {
786
- case "can't reach well-known oidc endpoint":
787
- return (
788
- await import("./diagnostic")
789
- ).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
790
- issuerUri
791
- });
792
- case "timeout":
793
- return (await import("./diagnostic")).createIframeTimeoutInitializationError(
794
- {
795
- redirectUri: homeUrlAndRedirectUri,
796
- clientId,
797
- issuerUri,
798
- noIframe
799
- }
800
- );
801
- }
802
-
803
- assert<Equals<typeof result_loginSilent.cause, never>>(false);
954
+ if (result_loginSilent.outcome === "timeout") {
955
+ return (await import("./diagnostic")).createIframeTimeoutInitializationError({
956
+ redirectUri: homeUrlAndRedirectUri,
957
+ clientId,
958
+ issuerUri,
959
+ noIframe
960
+ });
804
961
  }
805
962
 
806
963
  assert<Equals<typeof result_loginSilent.outcome, "got auth response from iframe">>();
@@ -864,9 +1021,7 @@ export async function createOidc_nonMemoized<
864
1021
  });
865
1022
  }
866
1023
 
867
- const dCantFetchWellKnownEndpointOrNever = new Deferred<void | never>();
868
-
869
- loginOrGoToAuthServer({
1024
+ await loginOrGoToAuthServer({
870
1025
  action: "login",
871
1026
  doForceReloadOnBfCache: true,
872
1027
  redirectUrl: getRootRelativeOriginalLocationHref(),
@@ -885,19 +1040,7 @@ export async function createOidc_nonMemoized<
885
1040
  }
886
1041
 
887
1042
  return "ensure no interaction";
888
- })(),
889
- onCantFetchWellKnownEndpointError: () => {
890
- dCantFetchWellKnownEndpointOrNever.resolve();
891
- }
892
- });
893
-
894
- await dCantFetchWellKnownEndpointOrNever.pr;
895
-
896
- return (
897
- await import("./diagnostic")
898
- ).createFailedToFetchTokenEndpointInitializationError({
899
- clientId,
900
- issuerUri
1043
+ })()
901
1044
  });
902
1045
  }
903
1046
 
@@ -1018,11 +1161,7 @@ export async function createOidc_nonMemoized<
1018
1161
  interaction:
1019
1162
  getPersistedAuthState({ configId }) === "explicitly logged out"
1020
1163
  ? "ensure interaction"
1021
- : "directly redirect if active session show login otherwise",
1022
- onCantFetchWellKnownEndpointError: () => {
1023
- log?.("Login called but the auth server seems to be down..");
1024
- alert("Authentication unavailable please try again later.");
1025
- }
1164
+ : "directly redirect if active session show login otherwise"
1026
1165
  });
1027
1166
  },
1028
1167
  initializationError: undefined
@@ -1254,16 +1393,7 @@ export async function createOidc_nonMemoized<
1254
1393
  extraQueryParams_local: undefined,
1255
1394
  transformUrlBeforeRedirect_local: undefined,
1256
1395
  doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
1257
- interaction: "directly redirect if active session show login otherwise",
1258
- onCantFetchWellKnownEndpointError: () => {
1259
- log?.(
1260
- [
1261
- "The auth server seems to be down while we needed to refresh the token",
1262
- "with a full page redirect. Reloading the page"
1263
- ].join(" ")
1264
- );
1265
- window.location.reload();
1266
- }
1396
+ interaction: "directly redirect if active session show login otherwise"
1267
1397
  });
1268
1398
  assert(false, "136134");
1269
1399
  };
@@ -1298,10 +1428,10 @@ export async function createOidc_nonMemoized<
1298
1428
  log
1299
1429
  });
1300
1430
 
1301
- if (result_loginSilent.outcome === "failure") {
1431
+ if (result_loginSilent.outcome === "timeout") {
1302
1432
  log?.(
1303
1433
  [
1304
- `Silent refresh of the token failed with ${result_loginSilent.cause}.`,
1434
+ `Silent refresh of the token failed the iframe didn't post a response (timeout).`,
1305
1435
  `This isn't recoverable, reloading the page.`
1306
1436
  ].join(" ")
1307
1437
  );
@@ -1491,11 +1621,7 @@ export async function createOidc_nonMemoized<
1491
1621
  action: "go to auth server",
1492
1622
  redirectUrl: redirectUrl ?? window.location.href,
1493
1623
  extraQueryParams_local: extraQueryParams,
1494
- transformUrlBeforeRedirect_local: transformUrlBeforeRedirect,
1495
- onCantFetchWellKnownEndpointError: () => {
1496
- log?.("goToAuthServer called but the auth server seems to be down..");
1497
- alert("Authentication unavailable please try again later.");
1498
- }
1624
+ transformUrlBeforeRedirect_local: transformUrlBeforeRedirect
1499
1625
  }),
1500
1626
  backFromAuthServer: resultOfLoginProcess.backFromAuthServer,
1501
1627
  isNewBrowserSession: (() => {
@@ -1,8 +1,7 @@
1
1
  import { OidcInitializationError } from "./OidcInitializationError";
2
2
  import { isKeycloak, createKeycloakUtils } from "../keycloak";
3
3
  import { getIsValidRemoteJson } from "../tools/getIsValidRemoteJson";
4
-
5
- export const WELL_KNOWN_PATH = "/.well-known/openid-configuration";
4
+ import { WELL_KNOWN_PATH } from "./OidcMetadata";
6
5
 
7
6
  export async function createWellKnownOidcConfigurationEndpointUnreachableInitializationError(params: {
8
7
  issuerUri: string;
@@ -95,6 +94,16 @@ export async function createIframeTimeoutInitializationError(params: {
95
94
  }): Promise<OidcInitializationError> {
96
95
  const { redirectUri, issuerUri, clientId, noIframe } = params;
97
96
 
97
+ check_if_well_known_endpoint_is_reachable: {
98
+ const isValid = await getIsValidRemoteJson(`${issuerUri}${WELL_KNOWN_PATH}`);
99
+
100
+ if (isValid) {
101
+ break check_if_well_known_endpoint_is_reachable;
102
+ }
103
+
104
+ return createWellKnownOidcConfigurationEndpointUnreachableInitializationError({ issuerUri });
105
+ }
106
+
98
107
  iframe_blocked: {
99
108
  if (noIframe) {
100
109
  break iframe_blocked;
@@ -233,6 +242,16 @@ export async function createFailedToFetchTokenEndpointInitializationError(params
233
242
  }) {
234
243
  const { issuerUri, clientId } = params;
235
244
 
245
+ check_if_well_known_endpoint_is_reachable: {
246
+ const isValid = await getIsValidRemoteJson(`${issuerUri}${WELL_KNOWN_PATH}`);
247
+
248
+ if (isValid) {
249
+ break check_if_well_known_endpoint_is_reachable;
250
+ }
251
+
252
+ return createWellKnownOidcConfigurationEndpointUnreachableInitializationError({ issuerUri });
253
+ }
254
+
236
255
  return new OidcInitializationError({
237
256
  isAuthServerLikelyDown: false,
238
257
  messageOrCause: [
@@ -7,6 +7,8 @@ import {
7
7
  preventSessionStorageSetItemOfPublicKeyByThirdParty
8
8
  } from "./iframeMessageProtection";
9
9
  import { setOidcRequiredPostHydrationReplaceNavigationUrl } from "./requiredPostHydrationReplaceNavigationUrl";
10
+ import { setBASE_URL } from "./BASE_URL";
11
+ import { resolvePrShouldLoadApp } from "./prShouldLoadApp";
10
12
  import { isBrowser } from "../tools/isBrowser";
11
13
 
12
14
  let hasEarlyInitBeenCalled = false;
@@ -18,6 +20,7 @@ export function oidcEarlyInit(params: {
18
20
  // Will be made mandatory next major.
19
21
  freezeWebSocket?: boolean;
20
22
  isPostLoginRedirectManual?: boolean;
23
+ BASE_URL?: string;
21
24
  }) {
22
25
  if (hasEarlyInitBeenCalled) {
23
26
  throw new Error("oidc-spa: oidcEarlyInit() Should be called only once");
@@ -35,8 +38,9 @@ export function oidcEarlyInit(params: {
35
38
  freezeFetch,
36
39
  freezeXMLHttpRequest,
37
40
  freezeWebSocket = false,
38
- isPostLoginRedirectManual = false
39
- } = params ?? {};
41
+ isPostLoginRedirectManual = false,
42
+ BASE_URL
43
+ } = params;
40
44
 
41
45
  const { shouldLoadApp } = handleOidcCallback({ isPostLoginRedirectManual });
42
46
 
@@ -83,8 +87,14 @@ export function oidcEarlyInit(params: {
83
87
  }
84
88
 
85
89
  preventSessionStorageSetItemOfPublicKeyByThirdParty();
90
+
91
+ if (BASE_URL !== undefined) {
92
+ setBASE_URL({ BASE_URL });
93
+ }
86
94
  }
87
95
 
96
+ resolvePrShouldLoadApp({ shouldLoadApp });
97
+
88
98
  return { shouldLoadApp };
89
99
  }
90
100
 
@@ -93,15 +103,8 @@ let redirectAuthResponse: AuthResponse | undefined = undefined;
93
103
  export function getRedirectAuthResponse():
94
104
  | { authResponse: AuthResponse; clearAuthResponse: () => void }
95
105
  | { authResponse: undefined; clearAuthResponse?: never } {
96
- if (!hasEarlyInitBeenCalled) {
97
- throw new Error(
98
- [
99
- "oidc-spa setup error.",
100
- "oidcEarlyInit() wasn't called.",
101
- "In newer version, using oidc-spa/entrypoint is no longer optional."
102
- ].join(" ")
103
- );
104
- }
106
+ assert(hasEarlyInitBeenCalled, "34933395");
107
+
105
108
  return redirectAuthResponse === undefined
106
109
  ? { authResponse: undefined }
107
110
  : {