oidc-spa 8.2.0 → 8.2.2

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 (84) hide show
  1. package/core/AuthResponse.d.ts +0 -5
  2. package/core/AuthResponse.js +0 -25
  3. package/core/AuthResponse.js.map +1 -1
  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 +4 -3
  8. package/core/createOidc.js +229 -197
  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/instancesThatCantUseIframes.d.ts +2 -0
  14. package/core/instancesThatCantUseIframes.js +20 -0
  15. package/core/instancesThatCantUseIframes.js.map +1 -0
  16. package/core/loginOrGoToAuthServer.d.ts +1 -1
  17. package/core/loginOrGoToAuthServer.js +4 -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/persistedAuthState.d.ts +1 -0
  23. package/core/persistedAuthState.js +14 -4
  24. package/core/persistedAuthState.js.map +1 -1
  25. package/esm/core/AuthResponse.d.ts +0 -5
  26. package/esm/core/AuthResponse.js +0 -23
  27. package/esm/core/AuthResponse.js.map +1 -1
  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 +4 -3
  32. package/esm/core/createOidc.js +230 -198
  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/instancesThatCantUseIframes.d.ts +2 -0
  38. package/esm/core/instancesThatCantUseIframes.js +16 -0
  39. package/esm/core/instancesThatCantUseIframes.js.map +1 -0
  40. package/esm/core/loginOrGoToAuthServer.d.ts +1 -1
  41. package/esm/core/loginOrGoToAuthServer.js +4 -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/persistedAuthState.d.ts +1 -0
  47. package/esm/core/persistedAuthState.js +14 -4
  48. package/esm/core/persistedAuthState.js.map +1 -1
  49. package/esm/keycloak/keycloakIssuerUriParsed.js +8 -1
  50. package/esm/keycloak/keycloakIssuerUriParsed.js.map +1 -1
  51. package/esm/tools/isLikelyDevServer.d.ts +1 -0
  52. package/esm/tools/isLikelyDevServer.js +14 -0
  53. package/esm/tools/isLikelyDevServer.js.map +1 -0
  54. package/esm/tools/{EphemeralSessionStorage.d.ts → lazySessionStorage.d.ts} +2 -4
  55. package/esm/tools/lazySessionStorage.js +81 -0
  56. package/esm/tools/lazySessionStorage.js.map +1 -0
  57. package/keycloak/keycloakIssuerUriParsed.js +8 -1
  58. package/keycloak/keycloakIssuerUriParsed.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/core/AuthResponse.ts +0 -36
  61. package/src/core/OidcMetadata.ts +75 -0
  62. package/src/core/createOidc.ts +277 -264
  63. package/src/core/diagnostic.ts +21 -2
  64. package/src/core/instancesThatCantUseIframes.ts +24 -0
  65. package/src/core/loginOrGoToAuthServer.ts +5 -22
  66. package/src/core/loginSilent.ts +4 -27
  67. package/src/core/persistedAuthState.ts +27 -5
  68. package/src/keycloak/keycloakIssuerUriParsed.ts +10 -1
  69. package/src/tools/isLikelyDevServer.ts +17 -0
  70. package/src/tools/lazySessionStorage.ts +119 -0
  71. package/src/vite-plugin/manageOptimizedDeps.ts +2 -0
  72. package/tools/isLikelyDevServer.d.ts +1 -0
  73. package/tools/isLikelyDevServer.js +17 -0
  74. package/tools/isLikelyDevServer.js.map +1 -0
  75. package/tools/{EphemeralSessionStorage.d.ts → lazySessionStorage.d.ts} +2 -4
  76. package/tools/lazySessionStorage.js +84 -0
  77. package/tools/lazySessionStorage.js.map +1 -0
  78. package/vite-plugin/manageOptimizedDeps.js +1 -0
  79. package/vite-plugin/manageOptimizedDeps.js.map +1 -1
  80. package/esm/tools/EphemeralSessionStorage.js +0 -143
  81. package/esm/tools/EphemeralSessionStorage.js.map +0 -1
  82. package/src/tools/EphemeralSessionStorage.ts +0 -225
  83. package/tools/EphemeralSessionStorage.js +0 -146
  84. package/tools/EphemeralSessionStorage.js.map +0 -1
@@ -1,4 +1,5 @@
1
1
  import { UserManager as OidcClientTsUserManager, WebStorageStateStore, InMemoryWebStorage } from "../vendor/frontend/oidc-client-ts";
2
+ import { fetchOidcMetadata } from "./OidcMetadata";
2
3
  import { assert, is } from "../tools/tsafe/assert";
3
4
  import { id } from "../tools/tsafe/id";
4
5
  import { setTimeout, clearTimeout } from "../tools/workerTimers";
@@ -14,38 +15,29 @@ import { notifyOtherTabsOfLogin, getPrOtherTabLogin } from "./loginPropagationTo
14
15
  import { getConfigId } from "./configId";
15
16
  import { oidcClientTsUserToTokens } from "./oidcClientTsUserToTokens";
16
17
  import { loginSilent } from "./loginSilent";
17
- import { authResponseToUrl, getPersistedRedirectAuthResponses, setPersistedRedirectAuthResponses } from "./AuthResponse";
18
+ import { authResponseToUrl } from "./AuthResponse";
18
19
  import { getRootRelativeOriginalLocationHref, getRedirectAuthResponse } from "./earlyInit";
19
20
  import { getPersistedAuthState, persistAuthState } from "./persistedAuthState";
20
21
  import { createEvt } from "../tools/Evt";
21
22
  import { getHaveSharedParentDomain } from "../tools/haveSharedParentDomain";
22
23
  import { createLoginOrGoToAuthServer, getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError } from "./loginOrGoToAuthServer";
23
- import { createEphemeralSessionStorage } from "../tools/EphemeralSessionStorage";
24
+ import { createLazySessionStorage } from "../tools/lazySessionStorage";
24
25
  import { startLoginOrRefreshProcess, waitForAllOtherOngoingLoginOrRefreshProcessesToComplete } from "./ongoingLoginOrRefreshProcesses";
25
26
  import { createGetIsNewBrowserSession } from "./isNewBrowserSession";
26
27
  import { getIsOnline } from "../tools/getIsOnline";
27
28
  import { isKeycloak } from "../keycloak/isKeycloak";
28
29
  import { INFINITY_TIME } from "../tools/INFINITY_TIME";
29
- import { getIsValidRemoteJson } from "../tools/getIsValidRemoteJson";
30
30
  import { prShouldLoadApp } from "./prShouldLoadApp";
31
31
  import { getBASE_URL } from "./BASE_URL";
32
+ import { getIsLikelyDevServer } from "../tools/isLikelyDevServer";
33
+ import { createObjectThatThrowsIfAccessed } from "../tools/createObjectThatThrowsIfAccessed";
34
+ import { evtIsThereMoreThanOneInstanceThatCantUserIframes, notifyNewInstanceThatCantUseIframes } from "./instancesThatCantUseIframes";
32
35
  // NOTE: Replaced at build time
33
- const VERSION = "8.2.0";
36
+ const VERSION = "8.2.2";
34
37
  const globalContext = {
35
38
  prOidcByConfigId: new Map(),
36
- hasLogoutBeenCalled: id(false),
37
- evtRequestToPersistTokens: createEvt()
39
+ hasLogoutBeenCalled: id(false)
38
40
  };
39
- globalContext.evtRequestToPersistTokens.subscribe(() => {
40
- const { authResponse } = getRedirectAuthResponse();
41
- if (authResponse === undefined) {
42
- return;
43
- }
44
- const { authResponses } = getPersistedRedirectAuthResponses();
45
- setPersistedRedirectAuthResponses({
46
- authResponses: [...authResponses, authResponse]
47
- });
48
- });
49
41
  /** @see: https://docs.oidc-spa.dev/v/v8/usage */
50
42
  export async function createOidc(params) {
51
43
  for (const name of ["issuerUri", "clientId"]) {
@@ -54,7 +46,7 @@ export async function createOidc(params) {
54
46
  throw new Error(`The parameter "${name}" is required, you provided: ${value}. (Forgot a .env variable?)`);
55
47
  }
56
48
  }
57
- const { issuerUri: issuerUri_params, clientId, scopes = ["profile"], debugLogs, ...rest } = params;
49
+ const { issuerUri: issuerUri_params, clientId, debugLogs, ...rest } = params;
58
50
  const issuerUri = toFullyQualifiedUrl({
59
51
  urlish: issuerUri_params,
60
52
  doAssertNoQueryParams: true,
@@ -96,7 +88,6 @@ export async function createOidc(params) {
96
88
  const oidc = await createOidc_nonMemoized(rest, {
97
89
  issuerUri,
98
90
  clientId,
99
- scopes,
100
91
  configId,
101
92
  log
102
93
  });
@@ -119,9 +110,9 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
119
110
  return new Promise(() => { });
120
111
  }
121
112
  }
122
- const { transformUrlBeforeRedirect, extraQueryParams: extraQueryParamsOrGetter, extraTokenParams: extraTokenParamsOrGetter, decodedIdTokenSchema, idleSessionLifetimeInSeconds, autoLogoutParams = { redirectTo: "current page" }, autoLogin = false, postLoginRedirectUrl: postLoginRedirectUrl_default, __unsafe_clientSecret, __unsafe_useIdTokenAsAccessToken = false, __metadata, noIframe = false } = params;
113
+ const { transformUrlBeforeRedirect, extraQueryParams: extraQueryParamsOrGetter, extraTokenParams: extraTokenParamsOrGetter, decodedIdTokenSchema, idleSessionLifetimeInSeconds, autoLogoutParams = { redirectTo: "current page" }, autoLogin = false, postLoginRedirectUrl: postLoginRedirectUrl_default, __unsafe_clientSecret, __unsafe_useIdTokenAsAccessToken = false, __metadata, noIframe = false, scopes = ["openid", "profile"] } = params;
123
114
  const BASE_URL_params = params.BASE_URL ?? params.homeUrl;
124
- const { issuerUri, clientId, scopes, configId, log } = preProcessedParams;
115
+ const { issuerUri, clientId, configId, log } = preProcessedParams;
125
116
  const getExtraQueryParams = (() => {
126
117
  if (extraQueryParamsOrGetter === undefined) {
127
118
  return undefined;
@@ -166,75 +157,174 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
166
157
  issuerUri,
167
158
  clientId,
168
159
  scopes,
169
- configId,
170
- homeUrlAndRedirectUri
160
+ oidcRedirectUri: homeUrlAndRedirectUri
171
161
  }, null, 2)}`);
172
162
  const stateUrlParamValue_instance = generateStateUrlParamValue();
163
+ const oidcMetadata = __metadata ?? (await fetchOidcMetadata({ issuerUri }));
173
164
  const canUseIframe = (() => {
174
165
  if (noIframe) {
175
166
  return false;
176
167
  }
177
168
  third_party_cookies: {
178
- const isOidcServerThirdPartyRelativeToApp = getHaveSharedParentDomain({
169
+ if (oidcMetadata === undefined) {
170
+ return false;
171
+ }
172
+ const { authorization_endpoint } = oidcMetadata;
173
+ assert(authorization_endpoint !== undefined, "Missing authorization_endpoint on the provided __metadata");
174
+ const isOidcServerThirdPartyRelativeToApp = !getHaveSharedParentDomain({
179
175
  url1: window.location.origin,
180
- url2: issuerUri
181
- }) === false;
176
+ // TODO: No, here we should test against the authorization endpoint!
177
+ url2: authorization_endpoint
178
+ });
182
179
  if (!isOidcServerThirdPartyRelativeToApp) {
183
180
  break third_party_cookies;
184
181
  }
185
- const isGoogleChrome = (() => {
186
- const ua = navigator.userAgent;
187
- const vendor = navigator.vendor;
188
- return (/Chrome/.test(ua) && /Google Inc/.test(vendor) && !/Edg/.test(ua) && !/OPR/.test(ua));
182
+ const isLikelyDevServer = getIsLikelyDevServer();
183
+ const domain_auth = new URL(authorization_endpoint).origin.split("//")[1];
184
+ assert(domain_auth !== undefined, "33921384");
185
+ const domain_here = window.location.origin.split("//")[1];
186
+ let isWellKnownProviderDomain = false;
187
+ let isIp = false;
188
+ const suggestedDeployments = (() => {
189
+ if (/^(?:\d{1,3}\.){3}\d{1,3}$|^\[?[A-Fa-f0-9:]+\]?$/.test(domain_auth)) {
190
+ isIp = true;
191
+ return [];
192
+ }
193
+ const baseDomain = (() => {
194
+ const segments = domain_auth.split(".");
195
+ if (segments.length >= 3) {
196
+ segments.shift();
197
+ }
198
+ return segments.join(".");
199
+ })();
200
+ {
201
+ const baseDomain_low = baseDomain.toLowerCase();
202
+ if (baseDomain_low.includes("auth0") ||
203
+ baseDomain_low.includes("clerk") ||
204
+ baseDomain_low.includes("microsoft") ||
205
+ baseDomain_low.includes("okta") ||
206
+ baseDomain_low.includes("aws")) {
207
+ isWellKnownProviderDomain = true;
208
+ return [];
209
+ }
210
+ }
211
+ const baseUrl = new URL(homeUrlAndRedirectUri).pathname;
212
+ return [
213
+ `myapp.${baseDomain}`,
214
+ baseDomain === domain_auth ? undefined : baseDomain,
215
+ `${baseDomain}/${baseUrl === "/" ? "dashboard" : baseUrl}`
216
+ ].filter(x => x !== undefined);
189
217
  })();
190
- if (window.location.origin.startsWith("http://localhost") && isGoogleChrome) {
191
- break third_party_cookies;
218
+ if (isLikelyDevServer) {
219
+ log?.([
220
+ "Detected localhost environment.",
221
+ "\nWhen reloading while logged in, you will briefly see",
222
+ "some URL params appear in the address bar.",
223
+ "\nThis happens because session restore via iframe is disabled,",
224
+ "the browser treats your auth server as a third party.",
225
+ `\nAuth server: ${domain_auth}`,
226
+ `\nApp domain: ${domain_here}`,
227
+ ...(() => {
228
+ if (isIp) {
229
+ return [];
230
+ }
231
+ if (isWellKnownProviderDomain) {
232
+ return [
233
+ "\nYou seem to be using a well-known auth provider.",
234
+ "Check your provider's docs, some allow configuring",
235
+ `a your custom domain at least for the authorization endpoint.`,
236
+ "\nIf configured, oidc-spa will restore sessions silently",
237
+ "and improve the user experience."
238
+ ];
239
+ }
240
+ return [
241
+ "\nOnce deployed under the same root domain as your auth server,",
242
+ "oidc-spa will use iframes to restore sessions silently.",
243
+ "\nSuggested deployments:",
244
+ ...suggestedDeployments.map(d => `\n • ${d}`)
245
+ ];
246
+ })(),
247
+ "\n\nMore info:",
248
+ "https://docs.oidc-spa.dev/v/v8/resources/end-of-third-party-cookies#when-are-cookies-considered-third-party"
249
+ ].join(" "));
250
+ }
251
+ else {
252
+ log?.([
253
+ "Silent session restore via iframe is disabled.",
254
+ `\nAuth server: ${domain_auth}`,
255
+ `App domain: ${domain_here}`,
256
+ "\nThey do not share a common root domain.",
257
+ ...(() => {
258
+ if (isIp) {
259
+ return [];
260
+ }
261
+ if (isWellKnownProviderDomain) {
262
+ return [
263
+ "\nYou seem to be using a well-known auth provider.",
264
+ "Check if you can configure a custom auth domain.",
265
+ "\nIf so, oidc-spa can restore sessions silently",
266
+ "and improve the user experience."
267
+ ];
268
+ }
269
+ return [
270
+ "\nTo improve the experience, here are some examples of deployment for your app:",
271
+ ...suggestedDeployments.map(d => `\n • ${d}`)
272
+ ];
273
+ })(),
274
+ "\nMore info:",
275
+ "https://docs.oidc-spa.dev/v/v8/resources/end-of-third-party-cookies#when-are-cookies-considered-third-party"
276
+ ].join(" "));
192
277
  }
193
- log?.([
194
- "Can't use iframe because your auth server is on a third party domain relative",
195
- "to the domain of your app and third party cookies are blocked by navigators."
196
- ].join(" "));
197
278
  return false;
198
279
  }
199
- // NOTE: Maybe not, it depend if the app can iframe itself.
200
280
  return true;
201
281
  })();
202
- let isUserStoreInMemoryOnly;
203
- const oidcClientTsUserManager = new OidcClientTsUserManager({
204
- stateUrlParamValue: stateUrlParamValue_instance,
205
- authority: issuerUri,
206
- client_id: clientId,
207
- redirect_uri: homeUrlAndRedirectUri,
208
- silent_redirect_uri: homeUrlAndRedirectUri,
209
- post_logout_redirect_uri: homeUrlAndRedirectUri,
210
- response_mode: isKeycloak({ issuerUri }) ? "fragment" : "query",
211
- response_type: "code",
212
- scope: Array.from(new Set(["openid", ...scopes])).join(" "),
213
- automaticSilentRenew: false,
214
- userStore: new WebStorageStateStore({
215
- store: (() => {
216
- if (canUseIframe) {
217
- isUserStoreInMemoryOnly = true;
218
- return new InMemoryWebStorage();
219
- }
220
- isUserStoreInMemoryOnly = false;
221
- const storage = createEphemeralSessionStorage({
222
- sessionStorageTtlMs: 3 * 60000
223
- });
224
- const { evtRequestToPersistTokens } = globalContext;
225
- evtRequestToPersistTokens.subscribe(({ configIdOfInstancePostingTheRequest }) => {
226
- if (configIdOfInstancePostingTheRequest === configId) {
227
- return;
282
+ notifyNewInstanceThatCantUseIframes();
283
+ if (evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
284
+ log?.([
285
+ "More than one oidc instance can't use iframe",
286
+ "falling back to persisting tokens in session storage"
287
+ ].join(" "));
288
+ }
289
+ const oidcClientTsUserManager = oidcMetadata === undefined
290
+ ? createObjectThatThrowsIfAccessed({
291
+ debugMessage: "oidc-spa: Wrong assertion 43943"
292
+ })
293
+ : new OidcClientTsUserManager({
294
+ stateUrlParamValue: stateUrlParamValue_instance,
295
+ authority: issuerUri,
296
+ client_id: clientId,
297
+ redirect_uri: homeUrlAndRedirectUri,
298
+ silent_redirect_uri: homeUrlAndRedirectUri,
299
+ post_logout_redirect_uri: homeUrlAndRedirectUri,
300
+ response_mode: isKeycloak({ issuerUri }) ? "fragment" : "query",
301
+ response_type: "code",
302
+ scope: Array.from(new Set(["openid", ...scopes])).join(" "),
303
+ automaticSilentRenew: false,
304
+ userStore: new WebStorageStateStore({
305
+ store: (() => {
306
+ if (canUseIframe) {
307
+ return new InMemoryWebStorage();
228
308
  }
229
- storage.persistCurrentStateAndSubsequentChanges();
230
- });
231
- return storage;
232
- })()
233
- }),
234
- stateStore: new WebStorageStateStore({ store: localStorage, prefix: STATE_STORE_KEY_PREFIX }),
235
- client_secret: __unsafe_clientSecret,
236
- metadata: __metadata
237
- });
309
+ const storage = createLazySessionStorage();
310
+ if (evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
311
+ storage.persistCurrentStateAndSubsequentChanges();
312
+ }
313
+ else {
314
+ evtIsThereMoreThanOneInstanceThatCantUserIframes.subscribe(() => {
315
+ storage.persistCurrentStateAndSubsequentChanges();
316
+ });
317
+ }
318
+ return storage;
319
+ })()
320
+ }),
321
+ stateStore: new WebStorageStateStore({
322
+ store: localStorage,
323
+ prefix: STATE_STORE_KEY_PREFIX
324
+ }),
325
+ client_secret: __unsafe_clientSecret,
326
+ metadata: oidcMetadata
327
+ });
238
328
  const evtInitializationOutcomeUserNotLoggedIn = createEvt();
239
329
  const { loginOrGoToAuthServer } = createLoginOrGoToAuthServer({
240
330
  configId,
@@ -252,54 +342,57 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
252
342
  });
253
343
  const { completeLoginOrRefreshProcess } = await startLoginOrRefreshProcess();
254
344
  const resultOfLoginProcess = await (async () => {
345
+ if (oidcMetadata === undefined) {
346
+ return (await import("./diagnostic")).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
347
+ issuerUri
348
+ });
349
+ }
350
+ restore_from_session_storage: {
351
+ if (canUseIframe) {
352
+ break restore_from_session_storage;
353
+ }
354
+ if (!evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
355
+ break restore_from_session_storage;
356
+ }
357
+ let oidcClientTsUser;
358
+ try {
359
+ oidcClientTsUser = await oidcClientTsUserManager.getUser();
360
+ }
361
+ catch {
362
+ // NOTE: Not sure if it can throw, but let's be safe.
363
+ oidcClientTsUser = null;
364
+ try {
365
+ await oidcClientTsUserManager.removeUser();
366
+ }
367
+ catch { }
368
+ }
369
+ if (oidcClientTsUser === null) {
370
+ break restore_from_session_storage;
371
+ }
372
+ log?.("Session was restored from session storage");
373
+ return {
374
+ oidcClientTsUser,
375
+ backFromAuthServer: undefined
376
+ };
377
+ }
255
378
  handle_redirect_auth_response: {
256
379
  let stateDataAndAuthResponse = undefined;
257
- get_stateData_and_authResponse: {
258
- from_memory: {
259
- const { authResponse, clearAuthResponse } = getRedirectAuthResponse();
260
- if (authResponse === undefined) {
261
- break from_memory;
262
- }
263
- const stateData = getStateData({ stateUrlParamValue: authResponse.state });
264
- if (stateData === undefined) {
265
- clearAuthResponse();
266
- break from_memory;
267
- }
268
- if (stateData.configId !== configId) {
269
- break from_memory;
270
- }
271
- assert(stateData.context === "redirect", "3229492");
380
+ {
381
+ const { authResponse, clearAuthResponse } = getRedirectAuthResponse();
382
+ if (authResponse === undefined) {
383
+ break handle_redirect_auth_response;
384
+ }
385
+ const stateData = getStateData({ stateUrlParamValue: authResponse.state });
386
+ if (stateData === undefined) {
272
387
  clearAuthResponse();
273
- stateDataAndAuthResponse = { stateData, authResponse };
274
- break get_stateData_and_authResponse;
388
+ break handle_redirect_auth_response;
275
389
  }
276
- // from storage, this is for race condition in multiple instance
277
- // setup where one instance would need to redirect before
278
- // the authResponse in memory had the chance to be processed.
279
- // This can only happen if:
280
- // 1) There are multiple oidc instances in the App.
281
- // 2) They are instantiated in a non deterministic order.
282
- // 3) We can't use iframe
283
- // We practically never persist the auth response and do it only in session
284
- // an ephemeral session storage, when we know it's gonna be required.
285
- {
286
- const { authResponses } = getPersistedRedirectAuthResponses();
287
- for (const authResponse of authResponses) {
288
- const stateData = getStateData({ stateUrlParamValue: authResponse.state });
289
- if (stateData === undefined) {
290
- continue;
291
- }
292
- if (stateData.configId !== configId) {
293
- continue;
294
- }
295
- assert(stateData.context === "redirect", "35935591");
296
- setPersistedRedirectAuthResponses({
297
- authResponses: authResponses.filter(authResponse_i => authResponse_i !== authResponse)
298
- });
299
- stateDataAndAuthResponse = { stateData, authResponse };
300
- break get_stateData_and_authResponse;
301
- }
390
+ if (stateData.configId !== configId) {
391
+ break handle_redirect_auth_response;
302
392
  }
393
+ assert(stateData.context === "redirect", "3229492");
394
+ clearAuthResponse();
395
+ stateDataAndAuthResponse = { stateData, authResponse };
303
396
  }
304
397
  if (stateDataAndAuthResponse === undefined) {
305
398
  break handle_redirect_auth_response;
@@ -378,33 +471,6 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
378
471
  assert(false);
379
472
  }
380
473
  }
381
- // NOTE: We almost never persist tokens, we have to only to support edge case
382
- // of multiple oidc instance in a single App with no iframe support.
383
- restore_from_session_storage: {
384
- if (isUserStoreInMemoryOnly) {
385
- break restore_from_session_storage;
386
- }
387
- let oidcClientTsUser;
388
- try {
389
- oidcClientTsUser = await oidcClientTsUserManager.getUser();
390
- }
391
- catch {
392
- // NOTE: Not sure if it can throw, but let's be safe.
393
- oidcClientTsUser = null;
394
- try {
395
- await oidcClientTsUserManager.removeUser();
396
- }
397
- catch { }
398
- }
399
- if (oidcClientTsUser === null) {
400
- break restore_from_session_storage;
401
- }
402
- log?.("Restored the auth from ephemeral session storage");
403
- return {
404
- oidcClientTsUser,
405
- backFromAuthServer: undefined
406
- };
407
- }
408
474
  silent_login_if_possible_and_auto_login: {
409
475
  const persistedAuthState = getPersistedAuthState({ configId });
410
476
  if (persistedAuthState === "explicitly logged out" && !autoLogin) {
@@ -438,11 +504,6 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
438
504
  break actual_silent_signin;
439
505
  }
440
506
  if (!canUseIframe) {
441
- if (!(await getIsValidRemoteJson(`${issuerUri}${id("/.well-known/openid-configuration")}`))) {
442
- return (await import("./diagnostic")).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
443
- issuerUri
444
- });
445
- }
446
507
  break actual_silent_signin;
447
508
  }
448
509
  log?.("Trying to restore the auth from the http only cookie (silent signin with iframe)");
@@ -457,21 +518,13 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
457
518
  log
458
519
  });
459
520
  assert(result_loginSilent.outcome !== "token refreshed using refresh token", "876995");
460
- if (result_loginSilent.outcome === "failure") {
461
- switch (result_loginSilent.cause) {
462
- case "can't reach well-known oidc endpoint":
463
- return (await import("./diagnostic")).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
464
- issuerUri
465
- });
466
- case "timeout":
467
- return (await import("./diagnostic")).createIframeTimeoutInitializationError({
468
- redirectUri: homeUrlAndRedirectUri,
469
- clientId,
470
- issuerUri,
471
- noIframe
472
- });
473
- }
474
- assert(false);
521
+ if (result_loginSilent.outcome === "timeout") {
522
+ return (await import("./diagnostic")).createIframeTimeoutInitializationError({
523
+ redirectUri: homeUrlAndRedirectUri,
524
+ clientId,
525
+ issuerUri,
526
+ noIframe
527
+ });
475
528
  }
476
529
  assert();
477
530
  const { authResponse } = result_loginSilent;
@@ -502,7 +555,6 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
502
555
  authResponse_error === "consent_required" ||
503
556
  authResponse_error === "account_selection_required"))) {
504
557
  log?.("Performing auto login with redirect");
505
- persistAuthState({ configId, state: undefined });
506
558
  completeLoginOrRefreshProcess();
507
559
  if (autoLogin && persistedAuthState !== "logged in") {
508
560
  evtInitializationOutcomeUserNotLoggedIn.post();
@@ -510,16 +562,15 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
510
562
  await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
511
563
  prUnlock: getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError()
512
564
  });
513
- if (persistedAuthState === "logged in") {
514
- globalContext.evtRequestToPersistTokens.post({
515
- configIdOfInstancePostingTheRequest: configId
516
- });
517
- }
518
- const dCantFetchWellKnownEndpointOrNever = new Deferred();
519
- loginOrGoToAuthServer({
565
+ await loginOrGoToAuthServer({
520
566
  action: "login",
521
567
  doForceReloadOnBfCache: true,
522
- redirectUrl: getRootRelativeOriginalLocationHref(),
568
+ redirectUrl: (() => {
569
+ if (evtIsThereMoreThanOneInstanceThatCantUserIframes.current) {
570
+ return window.location.href;
571
+ }
572
+ return getRootRelativeOriginalLocationHref();
573
+ })(),
523
574
  // NOTE: Wether or not it's the preferred behavior, pushing to history
524
575
  // only works on user interaction so it have to be false
525
576
  doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
@@ -534,15 +585,10 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
534
585
  }
535
586
  return "ensure no interaction";
536
587
  })(),
537
- onCantFetchWellKnownEndpointError: () => {
538
- dCantFetchWellKnownEndpointOrNever.resolve();
588
+ preRedirectHook: () => {
589
+ persistAuthState({ configId, state: undefined });
539
590
  }
540
591
  });
541
- await dCantFetchWellKnownEndpointOrNever.pr;
542
- return (await import("./diagnostic")).createFailedToFetchTokenEndpointInitializationError({
543
- clientId,
544
- issuerUri
545
- });
546
592
  }
547
593
  if (authResponse_error !== undefined) {
548
594
  log?.([
@@ -629,10 +675,7 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
629
675
  interaction: getPersistedAuthState({ configId }) === "explicitly logged out"
630
676
  ? "ensure interaction"
631
677
  : "directly redirect if active session show login otherwise",
632
- onCantFetchWellKnownEndpointError: () => {
633
- log?.("Login called but the auth server seems to be down..");
634
- alert("Authentication unavailable please try again later.");
635
- }
678
+ preRedirectHook: undefined
636
679
  });
637
680
  },
638
681
  initializationError: undefined
@@ -689,6 +732,7 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
689
732
  state: {
690
733
  stateDescription: "logged in",
691
734
  refreshTokenExpirationTime: currentTokens.refreshTokenExpirationTime,
735
+ serverDateNow: currentTokens.getServerDateNow(),
692
736
  idleSessionLifetimeInSeconds
693
737
  }
694
738
  });
@@ -806,9 +850,6 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
806
850
  await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
807
851
  prUnlock: new Promise(() => { })
808
852
  });
809
- globalContext.evtRequestToPersistTokens.post({
810
- configIdOfInstancePostingTheRequest: configId
811
- });
812
853
  await loginOrGoToAuthServer({
813
854
  action: "login",
814
855
  redirectUrl: window.location.href,
@@ -817,13 +858,7 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
817
858
  transformUrlBeforeRedirect_local: undefined,
818
859
  doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
819
860
  interaction: "directly redirect if active session show login otherwise",
820
- onCantFetchWellKnownEndpointError: () => {
821
- log?.([
822
- "The auth server seems to be down while we needed to refresh the token",
823
- "with a full page redirect. Reloading the page"
824
- ].join(" "));
825
- window.location.reload();
826
- }
861
+ preRedirectHook: undefined
827
862
  });
828
863
  assert(false, "136134");
829
864
  };
@@ -849,9 +884,9 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
849
884
  autoLogin,
850
885
  log
851
886
  });
852
- if (result_loginSilent.outcome === "failure") {
887
+ if (result_loginSilent.outcome === "timeout") {
853
888
  log?.([
854
- `Silent refresh of the token failed with ${result_loginSilent.cause}.`,
889
+ `Silent refresh of the token failed the iframe didn't post a response (timeout).`,
855
890
  `This isn't recoverable, reloading the page.`
856
891
  ].join(" "));
857
892
  window.location.reload();
@@ -915,6 +950,7 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
915
950
  state: {
916
951
  stateDescription: "logged in",
917
952
  refreshTokenExpirationTime: currentTokens.refreshTokenExpirationTime,
953
+ serverDateNow: currentTokens.getServerDateNow(),
918
954
  idleSessionLifetimeInSeconds
919
955
  }
920
956
  });
@@ -989,11 +1025,7 @@ export async function createOidc_nonMemoized(params, preProcessedParams) {
989
1025
  action: "go to auth server",
990
1026
  redirectUrl: redirectUrl ?? window.location.href,
991
1027
  extraQueryParams_local: extraQueryParams,
992
- transformUrlBeforeRedirect_local: transformUrlBeforeRedirect,
993
- onCantFetchWellKnownEndpointError: () => {
994
- log?.("goToAuthServer called but the auth server seems to be down..");
995
- alert("Authentication unavailable please try again later.");
996
- }
1028
+ transformUrlBeforeRedirect_local: transformUrlBeforeRedirect
997
1029
  }),
998
1030
  backFromAuthServer: resultOfLoginProcess.backFromAuthServer,
999
1031
  isNewBrowserSession: (() => {