@auth0/auth0-spa-js 2.15.0 → 2.16.0

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.
@@ -185,6 +185,16 @@ export declare class Auth0Client {
185
185
  */
186
186
  getTokenSilently(options?: GetTokenSilentlyOptions): Promise<string>;
187
187
  private _getTokenSilently;
188
+ /**
189
+ * Checks if an error should be handled by the interactive error handler.
190
+ * Currently only handles mfa_required; extensible for future error types.
191
+ */
192
+ private _isInteractiveError;
193
+ /**
194
+ * Handles MFA errors by opening a popup to complete authentication,
195
+ * then reads the resulting token from cache.
196
+ */
197
+ private _handleInteractiveErrorWithPopup;
188
198
  /**
189
199
  * ```js
190
200
  * const token = await auth0.getTokenWithPopup(options);
@@ -1,6 +1,12 @@
1
1
  import { ICache } from './cache';
2
2
  import type { Dpop } from './dpop/dpop';
3
3
  import { CompleteResponse } from './MyAccountApiClient';
4
+ /**
5
+ * Configuration option for automatic interactive error handling.
6
+ *
7
+ * - `'popup'`: SDK automatically opens Universal Login popup on MFA error
8
+ */
9
+ export type InteractiveErrorHandler = 'popup';
4
10
  export interface AuthorizationParams {
5
11
  /**
6
12
  * - `'page'`: displays the UI with a full page view
@@ -262,6 +268,21 @@ export interface Auth0ClientOptions {
262
268
  * The default setting is `false`.
263
269
  */
264
270
  useDpop?: boolean;
271
+ /**
272
+ * Configures automatic handling of interactive authentication errors.
273
+ *
274
+ * When set, the SDK intercepts `mfa_required` errors from `getTokenSilently()`
275
+ * and handles them automatically instead of throwing to the caller.
276
+ *
277
+ * - `'popup'`: Opens Universal Login in a popup to complete MFA.
278
+ * The original `authorizationParams` (audience, scope) are preserved.
279
+ * On success, the token is returned. On failure, popup errors are thrown.
280
+ *
281
+ * This option only affects `getTokenSilently()`. Other methods are not affected.
282
+ *
283
+ * @default undefined (MFA errors are thrown to the caller)
284
+ */
285
+ interactiveErrorHandler?: InteractiveErrorHandler;
265
286
  /**
266
287
  * URL parameters that will be sent back to the Authorization Server. This can be known parameters
267
288
  * defined by Auth0 or custom parameters that you define.
@@ -1,2 +1,2 @@
1
- declare const _default: "2.15.0";
1
+ declare const _default: "2.16.0";
2
2
  export default _default;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "@auth0/auth0-spa-js",
4
4
  "description": "Auth0 SDK for Single Page Applications using Authorization Code Grant Flow with PKCE",
5
5
  "license": "MIT",
6
- "version": "2.15.0",
6
+ "version": "2.16.0",
7
7
  "main": "dist/lib/auth0-spa-js.cjs.js",
8
8
  "types": "dist/typings/index.d.ts",
9
9
  "module": "dist/auth0-spa-js.production.esm.js",
@@ -883,37 +883,92 @@ export class Auth0Client {
883
883
  getTokenOptions.authorizationParams.audience || 'default'
884
884
  );
885
885
 
886
- return await this.lockManager.runWithLock(lockKey, 5000, async () => {
887
- // Check the cache a second time, because it may have been populated
888
- // by a previous call while this call was waiting to acquire the lock.
889
- if (cacheMode !== 'off') {
890
- const entry = await this._getEntryFromCache({
891
- scope: getTokenOptions.authorizationParams.scope,
892
- audience:
893
- getTokenOptions.authorizationParams.audience || DEFAULT_AUDIENCE,
894
- clientId: this.options.clientId
895
- });
896
-
897
- if (entry) {
898
- return entry;
886
+ try {
887
+ return await this.lockManager.runWithLock(lockKey, 5000, async () => {
888
+ // Check the cache a second time, because it may have been populated
889
+ // by a previous call while this call was waiting to acquire the lock.
890
+ if (cacheMode !== 'off') {
891
+ const entry = await this._getEntryFromCache({
892
+ scope: getTokenOptions.authorizationParams.scope,
893
+ audience:
894
+ getTokenOptions.authorizationParams.audience || DEFAULT_AUDIENCE,
895
+ clientId: this.options.clientId
896
+ });
897
+
898
+ if (entry) {
899
+ return entry;
900
+ }
899
901
  }
902
+
903
+ const authResult = this.options.useRefreshTokens
904
+ ? await this._getTokenUsingRefreshToken(getTokenOptions)
905
+ : await this._getTokenFromIFrame(getTokenOptions);
906
+
907
+ const { id_token, token_type, access_token, oauthTokenScope, expires_in } =
908
+ authResult;
909
+
910
+ return {
911
+ id_token,
912
+ token_type,
913
+ access_token,
914
+ ...(oauthTokenScope ? { scope: oauthTokenScope } : null),
915
+ expires_in
916
+ };
917
+ });
918
+ } catch (error) {
919
+ // Lock is already released - safe to open popup
920
+ if (this._isInteractiveError(error) && this.options.interactiveErrorHandler === 'popup') {
921
+ return await this._handleInteractiveErrorWithPopup(getTokenOptions);
900
922
  }
923
+ throw error;
924
+ }
925
+ }
901
926
 
902
- const authResult = this.options.useRefreshTokens
903
- ? await this._getTokenUsingRefreshToken(getTokenOptions)
904
- : await this._getTokenFromIFrame(getTokenOptions);
927
+ /**
928
+ * Checks if an error should be handled by the interactive error handler.
929
+ * Currently only handles mfa_required; extensible for future error types.
930
+ */
931
+ private _isInteractiveError(error: unknown): error is MfaRequiredError {
932
+ return error instanceof MfaRequiredError;
933
+ }
905
934
 
906
- const { id_token, token_type, access_token, oauthTokenScope, expires_in } =
907
- authResult;
935
+ /**
936
+ * Handles MFA errors by opening a popup to complete authentication,
937
+ * then reads the resulting token from cache.
938
+ */
939
+ private async _handleInteractiveErrorWithPopup(
940
+ options: GetTokenSilentlyOptions & {
941
+ authorizationParams: AuthorizationParams & { scope: string };
942
+ }
943
+ ): Promise<GetTokenSilentlyVerboseResponse> {
944
+ try {
945
+ await this.loginWithPopup({
946
+ authorizationParams: options.authorizationParams
947
+ });
908
948
 
909
- return {
910
- id_token,
911
- token_type,
912
- access_token,
913
- ...(oauthTokenScope ? { scope: oauthTokenScope } : null),
914
- expires_in
915
- };
916
- });
949
+ const entry = await this._getEntryFromCache({
950
+ scope: options.authorizationParams.scope,
951
+ audience:
952
+ options.authorizationParams.audience || DEFAULT_AUDIENCE,
953
+ clientId: this.options.clientId
954
+ });
955
+
956
+ if (!entry) {
957
+ throw new GenericError(
958
+ 'interactive_handler_cache_miss',
959
+ 'Token not found in cache after interactive authentication'
960
+ );
961
+ }
962
+
963
+ return entry;
964
+ } catch (error) {
965
+ // Expected errors (all GenericError subclasses):
966
+ // - PopupCancelledError: user closed the popup before completing login
967
+ // - PopupTimeoutError: popup did not complete within the allowed time
968
+ // - PopupOpenError: popup could not be opened (e.g. blocked by browser)
969
+ // - GenericError: authentication or cache miss errors
970
+ throw error;
971
+ }
917
972
  }
918
973
 
919
974
  /**
package/src/global.ts CHANGED
@@ -2,6 +2,13 @@ import { ICache } from './cache';
2
2
  import type { Dpop } from './dpop/dpop';
3
3
  import { CompleteResponse } from './MyAccountApiClient';
4
4
 
5
+ /**
6
+ * Configuration option for automatic interactive error handling.
7
+ *
8
+ * - `'popup'`: SDK automatically opens Universal Login popup on MFA error
9
+ */
10
+ export type InteractiveErrorHandler = 'popup';
11
+
5
12
  export interface AuthorizationParams {
6
13
  /**
7
14
  * - `'page'`: displays the UI with a full page view
@@ -296,6 +303,21 @@ export interface Auth0ClientOptions {
296
303
  */
297
304
  useDpop?: boolean;
298
305
 
306
+ /**
307
+ * Configures automatic handling of interactive authentication errors.
308
+ *
309
+ * When set, the SDK intercepts `mfa_required` errors from `getTokenSilently()`
310
+ * and handles them automatically instead of throwing to the caller.
311
+ *
312
+ * - `'popup'`: Opens Universal Login in a popup to complete MFA.
313
+ * The original `authorizationParams` (audience, scope) are preserved.
314
+ * On success, the token is returned. On failure, popup errors are thrown.
315
+ *
316
+ * This option only affects `getTokenSilently()`. Other methods are not affected.
317
+ *
318
+ * @default undefined (MFA errors are thrown to the caller)
319
+ */
320
+ interactiveErrorHandler?: InteractiveErrorHandler;
299
321
 
300
322
  /**
301
323
  * URL parameters that will be sent back to the Authorization Server. This can be known parameters
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export default '2.15.0';
1
+ export default '2.16.0';