@auth0/auth0-spa-js 2.13.0 → 2.14.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.
@@ -245,47 +245,71 @@ export declare class Auth0Client {
245
245
  private _releaseLockOnPageHide;
246
246
  private _requestToken;
247
247
  /**
248
- * Exchanges an external subject token for an Auth0 token via a token exchange request.
248
+ * ```js
249
+ * await auth0.loginWithCustomTokenExchange(options);
250
+ * ```
251
+ *
252
+ * Exchanges an external subject token for Auth0 tokens and logs the user in.
253
+ * This method implements the Custom Token Exchange grant as specified in RFC 8693.
254
+ *
255
+ * The exchanged tokens are automatically cached, establishing an authenticated session.
256
+ * After calling this method, you can use `getUser()`, `getIdTokenClaims()`, and
257
+ * `getTokenSilently()` to access the user's information and tokens.
249
258
  *
250
259
  * @param {CustomTokenExchangeOptions} options - The options required to perform the token exchange.
251
260
  *
252
261
  * @returns {Promise<TokenEndpointResponse>} A promise that resolves to the token endpoint response,
253
- * which contains the issued Auth0 tokens.
262
+ * which contains the issued Auth0 tokens (access_token, id_token, etc.).
254
263
  *
255
- * This method implements the token exchange grant as specified in RFC 8693 by first validating
256
- * the provided subject token type and then constructing a token request to the /oauth/token endpoint.
257
264
  * The request includes the following parameters:
258
- *
259
- * - `grant_type`: Hard-coded to "urn:ietf:params:oauth:grant-type:token-exchange".
260
- * - `subject_token`: The external token provided via the options.
261
- * - `subject_token_type`: The type of the external token (validated by this function).
262
- * - `scope`: A unique set of scopes, generated by merging the scopes supplied in the options
263
- * with the SDK’s default scopes.
264
- * - `audience`: The target audience from the options, with fallback to the SDK's authorization configuration.
265
- * - `organization`: Optional organization ID or name for authenticating the user in an organization context.
266
- * When provided, the organization ID will be present in the access token payload.
265
+ * - `grant_type`: "urn:ietf:params:oauth:grant-type:token-exchange"
266
+ * - `subject_token`: The external token to exchange
267
+ * - `subject_token_type`: The type identifier of the external token
268
+ * - `scope`: Merged scopes from the request and SDK defaults
269
+ * - `audience`: Target audience (defaults to SDK configuration)
270
+ * - `organization`: Optional organization ID/name for org-scoped authentication
267
271
  *
268
272
  * **Example Usage:**
269
273
  *
270
- * ```
271
- * // Define the token exchange options
272
- * const options: CustomTokenExchangeOptions = {
274
+ * ```js
275
+ * const options = {
273
276
  * subject_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...',
274
277
  * subject_token_type: 'urn:acme:legacy-system-token',
275
- * scope: "openid profile",
276
- * organization: "org_12345"
278
+ * scope: 'openid profile email',
279
+ * audience: 'https://api.example.com',
280
+ * organization: 'org_12345'
277
281
  * };
278
282
  *
279
- * // Exchange the external token for Auth0 tokens
280
283
  * try {
281
- * const tokenResponse = await instance.exchangeToken(options);
282
- * // Use tokenResponse.access_token, tokenResponse.id_token, etc.
283
- * // The organization ID will be present in the access token payload
284
+ * const tokenResponse = await auth0.loginWithCustomTokenExchange(options);
285
+ * console.log('Access token:', tokenResponse.access_token);
286
+ *
287
+ * // User is now logged in - access user info
288
+ * const user = await auth0.getUser();
289
+ * console.log('Logged in user:', user);
284
290
  * } catch (error) {
285
- * // Handle token exchange error
291
+ * console.error('Token exchange failed:', error);
286
292
  * }
287
293
  * ```
288
294
  */
295
+ loginWithCustomTokenExchange(options: CustomTokenExchangeOptions): Promise<TokenEndpointResponse>;
296
+ /**
297
+ * @deprecated Use `loginWithCustomTokenExchange()` instead. This method will be removed in the next major version.
298
+ *
299
+ * Exchanges an external subject token for Auth0 tokens.
300
+ *
301
+ * @param {CustomTokenExchangeOptions} options - The options required to perform the token exchange.
302
+ * @returns {Promise<TokenEndpointResponse>} A promise that resolves to the token endpoint response.
303
+ *
304
+ * **Example:**
305
+ * ```js
306
+ * // Instead of:
307
+ * const tokens = await auth0.exchangeToken(options);
308
+ *
309
+ * // Use:
310
+ * const tokens = await auth0.loginWithCustomTokenExchange(options);
311
+ * ```
312
+ */
289
313
  exchangeToken(options: CustomTokenExchangeOptions): Promise<TokenEndpointResponse>;
290
314
  protected _assertDpop(dpop: Dpop | undefined): asserts dpop is Dpop;
291
315
  /**
@@ -29,6 +29,10 @@ export declare const MISSING_REFRESH_TOKEN_ERROR_MESSAGE = "Missing Refresh Toke
29
29
  * @ignore
30
30
  */
31
31
  export declare const INVALID_REFRESH_TOKEN_ERROR_MESSAGE = "invalid refresh token";
32
+ /**
33
+ * @ignore
34
+ */
35
+ export declare const USER_BLOCKED_ERROR_MESSAGE = "user is blocked";
32
36
  /**
33
37
  * @ignore
34
38
  */
@@ -1,2 +1,2 @@
1
- declare const _default: "2.13.0";
1
+ declare const _default: "2.14.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.13.0",
6
+ "version": "2.14.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",
@@ -61,6 +61,7 @@ import {
61
61
  DEFAULT_SESSION_CHECK_EXPIRY_DAYS,
62
62
  DEFAULT_AUTH0_CLIENT,
63
63
  INVALID_REFRESH_TOKEN_ERROR_MESSAGE,
64
+ USER_BLOCKED_ERROR_MESSAGE,
64
65
  DEFAULT_NOW_PROVIDER,
65
66
  DEFAULT_FETCH_TIMEOUT_MS,
66
67
  DEFAULT_AUDIENCE
@@ -1297,18 +1298,25 @@ export class Auth0Client {
1297
1298
  audience: options.authorizationParams.audience || DEFAULT_AUDIENCE
1298
1299
  };
1299
1300
  } catch (e) {
1300
- if (
1301
- // The web worker didn't have a refresh token in memory so
1302
- // fallback to an iframe.
1303
- (e.message.indexOf(MISSING_REFRESH_TOKEN_ERROR_MESSAGE) > -1 ||
1304
- // A refresh token was found, but is it no longer valid
1305
- // and useRefreshTokensFallback is explicitly enabled. Fallback to an iframe.
1306
- (e.message &&
1307
- e.message.indexOf(INVALID_REFRESH_TOKEN_ERROR_MESSAGE) > -1)) &&
1308
- this.options.useRefreshTokensFallback
1309
- ) {
1310
- return await this._getTokenFromIFrame(options);
1301
+ if (e.message) {
1302
+ // Blocked users should be logged out immediately. No point attempting
1303
+ // iframe fallback as the authorization server will reject the request.
1304
+ if (e.message.includes(USER_BLOCKED_ERROR_MESSAGE)) {
1305
+ await this.logout({ openUrl: false });
1306
+ throw e;
1307
+ }
1308
+
1309
+ // For missing or invalid refresh tokens, attempt iframe fallback if configured.
1310
+ // The iframe may succeed if the user still has a valid session.
1311
+ if (
1312
+ (e.message.includes(MISSING_REFRESH_TOKEN_ERROR_MESSAGE) ||
1313
+ e.message.includes(INVALID_REFRESH_TOKEN_ERROR_MESSAGE)) &&
1314
+ this.options.useRefreshTokensFallback
1315
+ ) {
1316
+ return await this._getTokenFromIFrame(options);
1317
+ }
1311
1318
  }
1319
+
1312
1320
  if (e instanceof MfaRequiredError) {
1313
1321
  this.mfa.setMFAAuthDetails(
1314
1322
  e.mfa_token,
@@ -1496,51 +1504,58 @@ export class Auth0Client {
1496
1504
  */
1497
1505
 
1498
1506
  /**
1499
- * Exchanges an external subject token for an Auth0 token via a token exchange request.
1507
+ * ```js
1508
+ * await auth0.loginWithCustomTokenExchange(options);
1509
+ * ```
1510
+ *
1511
+ * Exchanges an external subject token for Auth0 tokens and logs the user in.
1512
+ * This method implements the Custom Token Exchange grant as specified in RFC 8693.
1513
+ *
1514
+ * The exchanged tokens are automatically cached, establishing an authenticated session.
1515
+ * After calling this method, you can use `getUser()`, `getIdTokenClaims()`, and
1516
+ * `getTokenSilently()` to access the user's information and tokens.
1500
1517
  *
1501
1518
  * @param {CustomTokenExchangeOptions} options - The options required to perform the token exchange.
1502
1519
  *
1503
1520
  * @returns {Promise<TokenEndpointResponse>} A promise that resolves to the token endpoint response,
1504
- * which contains the issued Auth0 tokens.
1521
+ * which contains the issued Auth0 tokens (access_token, id_token, etc.).
1505
1522
  *
1506
- * This method implements the token exchange grant as specified in RFC 8693 by first validating
1507
- * the provided subject token type and then constructing a token request to the /oauth/token endpoint.
1508
1523
  * The request includes the following parameters:
1509
- *
1510
- * - `grant_type`: Hard-coded to "urn:ietf:params:oauth:grant-type:token-exchange".
1511
- * - `subject_token`: The external token provided via the options.
1512
- * - `subject_token_type`: The type of the external token (validated by this function).
1513
- * - `scope`: A unique set of scopes, generated by merging the scopes supplied in the options
1514
- * with the SDK’s default scopes.
1515
- * - `audience`: The target audience from the options, with fallback to the SDK's authorization configuration.
1516
- * - `organization`: Optional organization ID or name for authenticating the user in an organization context.
1517
- * When provided, the organization ID will be present in the access token payload.
1524
+ * - `grant_type`: "urn:ietf:params:oauth:grant-type:token-exchange"
1525
+ * - `subject_token`: The external token to exchange
1526
+ * - `subject_token_type`: The type identifier of the external token
1527
+ * - `scope`: Merged scopes from the request and SDK defaults
1528
+ * - `audience`: Target audience (defaults to SDK configuration)
1529
+ * - `organization`: Optional organization ID/name for org-scoped authentication
1518
1530
  *
1519
1531
  * **Example Usage:**
1520
1532
  *
1521
- * ```
1522
- * // Define the token exchange options
1523
- * const options: CustomTokenExchangeOptions = {
1533
+ * ```js
1534
+ * const options = {
1524
1535
  * subject_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...',
1525
1536
  * subject_token_type: 'urn:acme:legacy-system-token',
1526
- * scope: "openid profile",
1527
- * organization: "org_12345"
1537
+ * scope: 'openid profile email',
1538
+ * audience: 'https://api.example.com',
1539
+ * organization: 'org_12345'
1528
1540
  * };
1529
1541
  *
1530
- * // Exchange the external token for Auth0 tokens
1531
1542
  * try {
1532
- * const tokenResponse = await instance.exchangeToken(options);
1533
- * // Use tokenResponse.access_token, tokenResponse.id_token, etc.
1534
- * // The organization ID will be present in the access token payload
1543
+ * const tokenResponse = await auth0.loginWithCustomTokenExchange(options);
1544
+ * console.log('Access token:', tokenResponse.access_token);
1545
+ *
1546
+ * // User is now logged in - access user info
1547
+ * const user = await auth0.getUser();
1548
+ * console.log('Logged in user:', user);
1535
1549
  * } catch (error) {
1536
- * // Handle token exchange error
1550
+ * console.error('Token exchange failed:', error);
1537
1551
  * }
1538
1552
  * ```
1539
1553
  */
1540
- async exchangeToken(
1554
+ async loginWithCustomTokenExchange(
1541
1555
  options: CustomTokenExchangeOptions
1542
1556
  ): Promise<TokenEndpointResponse> {
1543
1557
  return this._requestToken({
1558
+ ...options,
1544
1559
  grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
1545
1560
  subject_token: options.subject_token,
1546
1561
  subject_token_type: options.subject_token_type,
@@ -1554,6 +1569,29 @@ export class Auth0Client {
1554
1569
  });
1555
1570
  }
1556
1571
 
1572
+ /**
1573
+ * @deprecated Use `loginWithCustomTokenExchange()` instead. This method will be removed in the next major version.
1574
+ *
1575
+ * Exchanges an external subject token for Auth0 tokens.
1576
+ *
1577
+ * @param {CustomTokenExchangeOptions} options - The options required to perform the token exchange.
1578
+ * @returns {Promise<TokenEndpointResponse>} A promise that resolves to the token endpoint response.
1579
+ *
1580
+ * **Example:**
1581
+ * ```js
1582
+ * // Instead of:
1583
+ * const tokens = await auth0.exchangeToken(options);
1584
+ *
1585
+ * // Use:
1586
+ * const tokens = await auth0.loginWithCustomTokenExchange(options);
1587
+ * ```
1588
+ */
1589
+ async exchangeToken(
1590
+ options: CustomTokenExchangeOptions
1591
+ ): Promise<TokenEndpointResponse> {
1592
+ return this.loginWithCustomTokenExchange(options);
1593
+ }
1594
+
1557
1595
  protected _assertDpop(dpop: Dpop | undefined): asserts dpop is Dpop {
1558
1596
  if (!dpop) {
1559
1597
  throw new Error('`useDpop` option must be enabled before using DPoP.');
package/src/constants.ts CHANGED
@@ -41,6 +41,11 @@ export const MISSING_REFRESH_TOKEN_ERROR_MESSAGE = 'Missing Refresh Token';
41
41
  */
42
42
  export const INVALID_REFRESH_TOKEN_ERROR_MESSAGE = 'invalid refresh token';
43
43
 
44
+ /**
45
+ * @ignore
46
+ */
47
+ export const USER_BLOCKED_ERROR_MESSAGE = 'user is blocked';
48
+
44
49
  /**
45
50
  * @ignore
46
51
  */
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export default '2.13.0';
1
+ export default '2.14.0';