@asgardeo/auth-spa 0.1.10 → 0.2.3

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 (54) hide show
  1. package/README.md +29 -1
  2. package/dist/asgardeo-spa.production.esm.js +17 -17
  3. package/dist/asgardeo-spa.production.esm.js.map +1 -1
  4. package/dist/asgardeo-spa.production.js +11 -11
  5. package/dist/asgardeo-spa.production.js.map +1 -1
  6. package/dist/asgardeo-spa.production.min.js +1 -1
  7. package/dist/asgardeo-spa.production.min.js.map +1 -1
  8. package/dist/polyfilled/asgardeo-spa.production.esm.js +25 -25
  9. package/dist/polyfilled/asgardeo-spa.production.esm.js.map +1 -1
  10. package/dist/polyfilled/asgardeo-spa.production.js +12 -12
  11. package/dist/polyfilled/asgardeo-spa.production.js.map +1 -1
  12. package/dist/polyfilled/asgardeo-spa.production.min.js +1 -1
  13. package/dist/polyfilled/asgardeo-spa.production.min.js.map +1 -1
  14. package/dist/src/client.d.ts +2 -2
  15. package/dist/src/client.d.ts.map +1 -1
  16. package/dist/src/client.js +4 -2
  17. package/dist/src/client.js.map +1 -1
  18. package/dist/src/clients/main-thread-client.d.ts.map +1 -1
  19. package/dist/src/clients/main-thread-client.js +23 -9
  20. package/dist/src/clients/main-thread-client.js.map +1 -1
  21. package/dist/src/clients/web-worker-client.d.ts.map +1 -1
  22. package/dist/src/clients/web-worker-client.js +38 -16
  23. package/dist/src/clients/web-worker-client.js.map +1 -1
  24. package/dist/src/constants/session-management.d.ts +1 -0
  25. package/dist/src/constants/session-management.d.ts.map +1 -1
  26. package/dist/src/constants/session-management.js +1 -0
  27. package/dist/src/constants/session-management.js.map +1 -1
  28. package/dist/src/helpers/session-management-helper.d.ts.map +1 -1
  29. package/dist/src/helpers/session-management-helper.js +36 -22
  30. package/dist/src/helpers/session-management-helper.js.map +1 -1
  31. package/dist/src/models/client-config.d.ts +8 -0
  32. package/dist/src/models/client-config.d.ts.map +1 -1
  33. package/dist/src/public-api.d.ts +1 -0
  34. package/dist/src/public-api.d.ts.map +1 -1
  35. package/dist/src/public-api.js +2 -0
  36. package/dist/src/public-api.js.map +1 -1
  37. package/dist/src/utils/spa-utils.d.ts +45 -0
  38. package/dist/src/utils/spa-utils.d.ts.map +1 -1
  39. package/dist/src/utils/spa-utils.js +70 -1
  40. package/dist/src/utils/spa-utils.js.map +1 -1
  41. package/dist/src/worker/worker-core.d.ts.map +1 -1
  42. package/dist/src/worker/worker-core.js +13 -4
  43. package/dist/src/worker/worker-core.js.map +1 -1
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +2 -2
  46. package/src/client.ts +8 -4
  47. package/src/clients/main-thread-client.ts +30 -12
  48. package/src/clients/web-worker-client.ts +46 -18
  49. package/src/constants/session-management.ts +1 -0
  50. package/src/helpers/session-management-helper.ts +45 -21
  51. package/src/models/client-config.ts +9 -0
  52. package/src/public-api.ts +3 -0
  53. package/src/utils/spa-utils.ts +72 -1
  54. package/src/worker/worker-core.ts +19 -15
@@ -297,14 +297,14 @@ export const MainThreadClient = async (
297
297
  ): Promise<BasicUserInfo> => {
298
298
  const config = await _dataLayer.getConfigData();
299
299
 
300
- const isLoggingOut = await _sessionManagementHelper.receivePromptNoneResponse(
300
+ const shouldStopContinue = await _sessionManagementHelper.receivePromptNoneResponse(
301
301
  async (sessionState: string | null) => {
302
302
  await _dataLayer.setSessionDataParameter(SESSION_STATE, sessionState ?? "");
303
303
  return;
304
304
  }
305
305
  );
306
306
 
307
- if (isLoggingOut) {
307
+ if (shouldStopContinue) {
308
308
  return Promise.resolve({
309
309
  allowedScopes: "",
310
310
  displayName: "",
@@ -322,7 +322,11 @@ export const MainThreadClient = async (
322
322
  if (await _authenticationClient.isAuthenticated()) {
323
323
  _spaHelper.clearRefreshTokenTimeout();
324
324
  _spaHelper.refreshAccessTokenAutomatically();
325
- checkSession();
325
+
326
+ // Enable OIDC Sessions Management only if it is set to true in the config.
327
+ if (config.enableOIDCSessionManagement) {
328
+ checkSession();
329
+ }
326
330
 
327
331
  return Promise.resolve(await _authenticationClient.getBasicUserInfo());
328
332
  }
@@ -371,6 +375,8 @@ export const MainThreadClient = async (
371
375
 
372
376
  location.href = url;
373
377
 
378
+ await SPAUtils.waitTillPageRedirect();
379
+
374
380
  return Promise.resolve({
375
381
  allowedScopes: "",
376
382
  displayName: "",
@@ -391,10 +397,12 @@ export const MainThreadClient = async (
391
397
 
392
398
  _spaHelper.clearRefreshTokenTimeout();
393
399
 
400
+ await SPAUtils.waitTillPageRedirect();
401
+
394
402
  return true;
395
403
  };
396
404
 
397
- const requestCustomGrant = async(config: CustomGrantConfig): Promise<BasicUserInfo | HttpResponse> => {
405
+ const requestCustomGrant = async (config: CustomGrantConfig): Promise<BasicUserInfo | HttpResponse> => {
398
406
  let useDefaultEndpoint = true;
399
407
  let matches = false;
400
408
  const clientConfig = await _dataLayer.getConfigData();
@@ -436,8 +444,8 @@ export const MainThreadClient = async (
436
444
  "requestCustomGrant",
437
445
  "Request to the provided endpoint is prohibited.",
438
446
  "Requests can only be sent to resource servers specified by the `resourceServerURLs`" +
439
- " attribute while initializing the SDK. The specified token endpoint in this request " +
440
- "cannot be found among the `resourceServerURLs`"
447
+ " attribute while initializing the SDK. The specified token endpoint in this request " +
448
+ "cannot be found among the `resourceServerURLs`"
441
449
  )
442
450
  );
443
451
  }
@@ -488,7 +496,11 @@ export const MainThreadClient = async (
488
496
 
489
497
  _spaHelper.clearRefreshTokenTimeout();
490
498
  _spaHelper.refreshAccessTokenAutomatically();
491
- checkSession();
499
+
500
+ // Enable OIDC Sessions Management only if it is set to true in the config.
501
+ if (config.enableOIDCSessionManagement) {
502
+ checkSession();
503
+ }
492
504
 
493
505
  return _authenticationClient.getBasicUserInfo();
494
506
  })
@@ -555,28 +567,34 @@ export const MainThreadClient = async (
555
567
  }
556
568
 
557
569
  return new Promise((resolve, reject) => {
558
- const listenToPrompNoneIFrame = async (e: MessageEvent) => {
570
+ const listenToPromptNoneIFrame = async (e: MessageEvent) => {
559
571
  const data: Message<AuthorizationInfo | null> = e.data;
572
+ const timer = setTimeout(() => {
573
+ resolve(false);
574
+ }, 10000);
560
575
 
561
576
  if (data?.type == CHECK_SESSION_SIGNED_OUT) {
562
- window.removeEventListener("message", listenToPrompNoneIFrame);
577
+ window.removeEventListener("message", listenToPromptNoneIFrame);
578
+ clearTimeout(timer);
563
579
  resolve(false);
564
580
  }
565
581
 
566
582
  if (data?.type == CHECK_SESSION_SIGNED_IN && data?.data?.code) {
567
583
  requestAccessToken(data.data.code, data?.data?.sessionState)
568
584
  .then((response: BasicUserInfo) => {
569
- window.removeEventListener("message", listenToPrompNoneIFrame);
585
+ window.removeEventListener("message", listenToPromptNoneIFrame);
586
+ clearTimeout(timer);
570
587
  resolve(response);
571
588
  })
572
589
  .catch((error) => {
573
- window.removeEventListener("message", listenToPrompNoneIFrame);
590
+ window.removeEventListener("message", listenToPromptNoneIFrame);
591
+ clearTimeout(timer);
574
592
  reject(error);
575
593
  });
576
594
  }
577
595
  };
578
596
 
579
- window.addEventListener("message", listenToPrompNoneIFrame);
597
+ window.addEventListener("message", listenToPromptNoneIFrame);
580
598
  });
581
599
  };
582
600
 
@@ -329,6 +329,7 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
329
329
  const trySignInSilently = async (): Promise<BasicUserInfo | boolean> => {
330
330
  const config: AuthClientConfig<WebWorkerClientConfig> = await getConfigData();
331
331
 
332
+ // This block is executed by the iFrame when the server redirects with the authorization code.
332
333
  if (SPAUtils.setIsInitializedSilentSignIn()) {
333
334
  await _sessionManagementHelper.receivePromptNoneResponse();
334
335
 
@@ -343,6 +344,11 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
343
344
  }
344
345
 
345
346
  if (SPAUtils.isStatePresentInURL()) {
347
+ // The state that is used to detect the auth request sent by this method is not there in the URL.
348
+ // Happens if it is the first time this method is being called.
349
+ // Or when this method is called inside the iFrame during the check session execution.
350
+
351
+ // This reverses the silent sign in flag being set to true by the previous code block.
346
352
  SPAUtils.setIsInitializedSilentSignIn();
347
353
 
348
354
  return Promise.resolve({
@@ -355,6 +361,7 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
355
361
  });
356
362
  }
357
363
 
364
+ // This gets executed in the main thread and sends the prompt none request.
358
365
  const rpIFrame = document.getElementById(RP_IFRAME) as HTMLIFrameElement;
359
366
 
360
367
  const promptNoneIFrame: HTMLIFrameElement = rpIFrame?.contentDocument?.getElementById(
@@ -380,27 +387,33 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
380
387
  }
381
388
 
382
389
  return new Promise((resolve, reject) => {
383
- const listenToPrompNoneIFrame = async (e: MessageEvent) => {
390
+ const listenToPromptNoneIFrame = async (e: MessageEvent) => {
384
391
  const data: Message<AuthorizationInfo | null> = e.data;
392
+ const timer = setTimeout(() => {
393
+ resolve(false);
394
+ }, 10000);
385
395
 
386
396
  if (data?.type == CHECK_SESSION_SIGNED_OUT) {
387
- window.removeEventListener("message", listenToPrompNoneIFrame);
397
+ window.removeEventListener("message", listenToPromptNoneIFrame);
398
+ clearTimeout(timer);
388
399
  resolve(false);
389
400
  }
390
401
 
391
402
  if (data?.type == CHECK_SESSION_SIGNED_IN && data?.data?.code) {
392
403
  requestAccessToken(data?.data?.code, data?.data?.sessionState).then((response: BasicUserInfo) => {
393
- window.removeEventListener("message", listenToPrompNoneIFrame);
404
+ window.removeEventListener("message", listenToPromptNoneIFrame);
405
+ clearTimeout(timer);
394
406
  resolve(response);
395
407
  }).catch((error) => {
396
- window.removeEventListener("message", listenToPrompNoneIFrame);
408
+ window.removeEventListener("message", listenToPromptNoneIFrame);
409
+ clearTimeout(timer);
397
410
  reject(error);
398
411
  })
399
412
 
400
413
  }
401
414
  };
402
415
 
403
- window.addEventListener("message", listenToPrompNoneIFrame)
416
+ window.addEventListener("message", listenToPromptNoneIFrame);
404
417
  });
405
418
  };
406
419
 
@@ -430,7 +443,13 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
430
443
  return communicate<null, string>(message)
431
444
  .then((url: string) => {
432
445
  SPAUtils.setSignOutURL(url);
433
- checkSession();
446
+
447
+ // Enable OIDC Sessions Management only if it is set to true in the config.
448
+ if (config.enableOIDCSessionManagement) {
449
+ checkSession();
450
+ }
451
+
452
+ startAutoRefreshToken();
434
453
 
435
454
  return Promise.resolve(response);
436
455
  })
@@ -455,13 +474,13 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
455
474
  ): Promise<BasicUserInfo> => {
456
475
  const config: AuthClientConfig<WebWorkerClientConfig> = await getConfigData();
457
476
 
458
- const isLoggingOut = await _sessionManagementHelper.receivePromptNoneResponse(
477
+ const shouldStopContinue = await _sessionManagementHelper.receivePromptNoneResponse(
459
478
  async (sessionState: string | null) => {
460
479
  return setSessionState(sessionState);
461
480
  }
462
481
  );
463
482
 
464
- if (isLoggingOut) {
483
+ if (shouldStopContinue) {
465
484
  return Promise.resolve({
466
485
  allowedScopes: "",
467
486
  displayName: "",
@@ -499,7 +518,11 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
499
518
 
500
519
  if (await isAuthenticated()) {
501
520
  await startAutoRefreshToken();
502
- checkSession();
521
+
522
+ // Enable OIDC Sessions Management only if it is set to true in the config.
523
+ if (config.enableOIDCSessionManagement) {
524
+ checkSession();
525
+ }
503
526
 
504
527
  return getBasicUserInfo();
505
528
  }
@@ -526,13 +549,15 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
526
549
  };
527
550
 
528
551
  return communicate<GetAuthURLConfig, AuthorizationResponse>(message)
529
- .then((response) => {
552
+ .then(async (response) => {
530
553
  if (response.pkce && config.enablePKCE) {
531
554
  SPAUtils.setPKCE(response.pkce);
532
555
  }
533
556
 
534
557
  location.href = response.authorizationURL;
535
558
 
559
+ await SPAUtils.waitTillPageRedirect();
560
+
536
561
  return Promise.resolve({
537
562
  allowedScopes: "",
538
563
  displayName: "",
@@ -554,16 +579,18 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
554
579
  */
555
580
  const signOut = (): Promise<boolean> => {
556
581
  return isAuthenticated()
557
- .then((response: boolean) => {
582
+ .then(async (response: boolean) => {
558
583
  if (response) {
559
584
  const message: Message<null> = {
560
585
  type: SIGN_OUT
561
586
  };
562
587
 
563
588
  return communicate<null, string>(message)
564
- .then((response) => {
589
+ .then(async (response) => {
565
590
  window.location.href = response;
566
591
 
592
+ await SPAUtils.waitTillPageRedirect();
593
+
567
594
  return Promise.resolve(true);
568
595
  })
569
596
  .catch((error) => {
@@ -572,6 +599,8 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
572
599
  } else {
573
600
  window.location.href = SPAUtils.getSignOutURL();
574
601
 
602
+ await SPAUtils.waitTillPageRedirect();
603
+
575
604
  return Promise.resolve(true);
576
605
  }
577
606
  })
@@ -618,14 +647,14 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
618
647
  type: GET_CONFIG_DATA
619
648
  };
620
649
 
621
- return communicate< null, AuthClientConfig<WebWorkerClientConfig>>(message)
650
+ return communicate<null, AuthClientConfig<WebWorkerClientConfig>>(message)
622
651
  .then((response) => {
623
652
  return Promise.resolve(response);
624
653
  })
625
654
  .catch((error) => {
626
655
  return Promise.reject(error);
627
- })
628
- }
656
+ });
657
+ };
629
658
 
630
659
  const getBasicUserInfo = (): Promise<BasicUserInfo> => {
631
660
  const message: Message<null> = {
@@ -715,9 +744,8 @@ export const WebWorkerClient = (config: AuthClientConfig<WebWorkerClientConfig>)
715
744
  }
716
745
  };
717
746
 
718
- const updateConfig = async(newConfig: Partial<AuthClientConfig<WebWorkerClientConfig>>): Promise<void> => {
719
-
720
- const config = { ...await getConfigData(), ...newConfig };
747
+ const updateConfig = async (newConfig: Partial<AuthClientConfig<WebWorkerClientConfig>>): Promise<void> => {
748
+ const config = { ...(await getConfigData()), ...newConfig };
721
749
 
722
750
  const message: Message<Partial<AuthClientConfig<WebWorkerClientConfig>>> = {
723
751
  data: config,
@@ -23,3 +23,4 @@ export const STATE = "Y2hlY2tTZXNzaW9u";
23
23
  export const SILENT_SIGN_IN_STATE = "sign-in-silently";
24
24
  export const INITIALIZED_SIGN_IN = "initialized-sign-in";
25
25
  export const INITIALIZED_SILENT_SIGN_IN = "initialized-silent-sign-in";
26
+ export const PROMPT_NONE_REQUEST_SENT = "promptNoneRequestSent";
@@ -17,6 +17,7 @@
17
17
  */
18
18
 
19
19
  import { SESSION_STATE } from "@asgardeo/auth-js";
20
+ import { SPAUtils } from "..";
20
21
  import {
21
22
  CHECK_SESSION_SIGNED_IN,
22
23
  CHECK_SESSION_SIGNED_OUT,
@@ -134,7 +135,7 @@ export const SessionManagementHelper = (() => {
134
135
  if (e.data === "unchanged") {
135
136
  // [RP] session state has not changed
136
137
  } else if (e.data === "error") {
137
- window.top.location.href = await _signOut();
138
+ window.parent.location.href = await _signOut();
138
139
  } else {
139
140
  // [RP] session state has changed. Sending prompt=none request...
140
141
  sendPromptNoneRequest();
@@ -150,19 +151,24 @@ export const SessionManagementHelper = (() => {
150
151
  const promptNoneIFrame: HTMLIFrameElement = rpIFrame?.contentDocument?.getElementById(
151
152
  PROMPT_NONE_IFRAME
152
153
  ) as HTMLIFrameElement;
153
- promptNoneIFrame.src =
154
- _authorizationEndpoint +
155
- "?response_type=code" +
156
- "&client_id=" +
157
- _clientID +
158
- "&scope=openid" +
159
- "&redirect_uri=" +
160
- _redirectURL +
161
- "&state=" +
162
- STATE +
163
- "&prompt=none" +
164
- "&code_challenge_method=S256&code_challenge=" +
165
- getRandomPKCEChallenge();
154
+
155
+ if (SPAUtils.canSendPromptNoneRequest()) {
156
+ SPAUtils.setPromptNoneRequestSent(true);
157
+
158
+ promptNoneIFrame.src =
159
+ _authorizationEndpoint +
160
+ "?response_type=code" +
161
+ "&client_id=" +
162
+ _clientID +
163
+ "&scope=openid" +
164
+ "&redirect_uri=" +
165
+ _redirectURL +
166
+ "&state=" +
167
+ STATE +
168
+ "&prompt=none" +
169
+ "&code_challenge_method=S256&code_challenge=" +
170
+ getRandomPKCEChallenge();
171
+ }
166
172
  };
167
173
 
168
174
  /**
@@ -176,6 +182,7 @@ export const SessionManagementHelper = (() => {
176
182
  ): Promise<boolean> => {
177
183
  const state = new URL(window.location.href).searchParams.get("state");
178
184
  const sessionState = new URL(window.location.href).searchParams.get(SESSION_STATE);
185
+ const parent = window.parent.parent;
179
186
 
180
187
  if (state !== null && (state === STATE || state === SILENT_SIGN_IN_STATE)) {
181
188
  // Prompt none response.
@@ -192,17 +199,26 @@ export const SessionManagementHelper = (() => {
192
199
  };
193
200
 
194
201
  sessionStorage.setItem(INITIALIZED_SILENT_SIGN_IN, "false");
195
- window.top.postMessage(message, window.top.origin);
202
+ parent.postMessage(message, parent.origin);
203
+ SPAUtils.setPromptNoneRequestSent(false);
204
+
196
205
  window.location.href = "about:blank";
197
206
 
207
+ await SPAUtils.waitTillPageRedirect();
208
+
198
209
  return true;
199
210
  }
200
211
 
201
212
  const newSessionState = new URL(window.location.href).searchParams.get("session_state");
202
213
 
203
214
  setSessionState && await setSessionState(newSessionState);
215
+ SPAUtils.setPromptNoneRequestSent(false);
216
+
217
+ window.location.href = "about:blank";
204
218
 
205
- window.stop();
219
+ await SPAUtils.waitTillPageRedirect();
220
+
221
+ return true;
206
222
  } else {
207
223
  if (state === SILENT_SIGN_IN_STATE) {
208
224
  const message: Message<null> = {
@@ -210,15 +226,23 @@ export const SessionManagementHelper = (() => {
210
226
  };
211
227
 
212
228
  sessionStorage.setItem(INITIALIZED_SILENT_SIGN_IN, "false");
213
- window.top.postMessage(message, window.top.origin);
229
+ window.parent.parent.postMessage(message, parent.origin);
230
+ SPAUtils.setPromptNoneRequestSent(false);
231
+
214
232
  window.location.href = "about:blank";
215
233
 
234
+ await SPAUtils.waitTillPageRedirect();
235
+
216
236
  return true;
217
237
  }
218
238
 
219
- window.top.location.href = await _signOut();
239
+ SPAUtils.setPromptNoneRequestSent(false);
240
+
241
+ parent.location.href = await _signOut();
220
242
  window.location.href = "about:blank";
221
243
 
244
+ await SPAUtils.waitTillPageRedirect();
245
+
222
246
  return true;
223
247
  }
224
248
  }
@@ -239,10 +263,10 @@ export const SessionManagementHelper = (() => {
239
263
  promptNoneIFrame.setAttribute("id", PROMPT_NONE_IFRAME);
240
264
  promptNoneIFrame.style.display = "none";
241
265
 
242
- document.body.appendChild(rpIFrame);
266
+ document?.body?.appendChild(rpIFrame);
243
267
  rpIFrame = document.getElementById(RP_IFRAME) as HTMLIFrameElement;
244
- rpIFrame?.contentDocument?.body.appendChild(opIFrame);
245
- rpIFrame?.contentDocument?.body.appendChild(promptNoneIFrame);
268
+ rpIFrame?.contentDocument?.body?.appendChild(opIFrame);
269
+ rpIFrame?.contentDocument?.body?.appendChild(promptNoneIFrame);
246
270
 
247
271
  _signOut = signOut;
248
272
 
@@ -16,10 +16,17 @@
16
16
  * under the License.
17
17
  */
18
18
 
19
+ import { AuthClientConfig } from "@asgardeo/auth-js";
19
20
  import { Storage } from "../constants";
20
21
 
21
22
 
22
23
  export interface SPAConfig {
24
+ /**
25
+ * Enable OIDC Session Management with PR Iframe.
26
+ * @remarks If the consumer app the OP is hosted in different domains,
27
+ * third party cookies has to be enabled for this to work properly.
28
+ */
29
+ enableOIDCSessionManagement?: boolean;
23
30
  checkSessionInterval?: number;
24
31
  sessionRefreshInterval?: number;
25
32
  resourceServerURLs?: string[];
@@ -38,3 +45,5 @@ export interface WebWorkerClientConfig extends SPAConfig {
38
45
  }
39
46
 
40
47
  export type Config = MainThreadClientConfig | WebWorkerClientConfig;
48
+
49
+ export type AuthSPAClientConfig = AuthClientConfig<Config>;