@auth0/auth0-server-js 1.8.0 → 1.10.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.
package/dist/index.js CHANGED
@@ -163,6 +163,7 @@ function updateStateDataForConnectionTokenSet(options, stateData, tokenEndpointR
163
163
  import {
164
164
  TokenForConnectionError,
165
165
  AuthClient,
166
+ OrganizationValidationError,
166
167
  PasswordlessStartError,
167
168
  PasswordlessVerifyError,
168
169
  TokenByRefreshTokenError
@@ -204,7 +205,7 @@ function getTelemetryConfig(config) {
204
205
  return {
205
206
  enabled: true,
206
207
  name: config?.name ?? "@auth0/auth0-server-js",
207
- version: config?.version ?? "1.8.0"
208
+ version: config?.version ?? "1.10.0"
208
209
  };
209
210
  }
210
211
 
@@ -383,6 +384,53 @@ var ServerPasskeyClient = class {
383
384
  }
384
385
  };
385
386
 
387
+ // src/database/server-database-client.ts
388
+ var ServerDatabaseClient = class {
389
+ #options;
390
+ /**
391
+ * @internal
392
+ */
393
+ constructor(options) {
394
+ this.#options = options;
395
+ }
396
+ /**
397
+ * Registers a new user in a database connection.
398
+ *
399
+ * Delegates to the underlying `AuthClient.database.signUp` without any session
400
+ * state modification. The caller is responsible for handling the returned user
401
+ * data as needed.
402
+ *
403
+ * @param options The signup options (email, password, connection, etc.).
404
+ * @param storeOptions Optional options used to resolve the domain (resolver mode).
405
+ *
406
+ * @throws {SignUpError} If there was an issue signing the user up.
407
+ *
408
+ * @returns A promise resolving to the created user result with a normalized `id` field.
409
+ */
410
+ async signUp(options, storeOptions) {
411
+ const domain = await this.#options.resolveDomain(storeOptions);
412
+ return this.#options.getAuthClient(domain).database.signUp(options);
413
+ }
414
+ /**
415
+ * Requests a password-change email for a database connection user.
416
+ *
417
+ * Delegates to the underlying `AuthClient.database.changePassword` without any
418
+ * session state modification. The caller is responsible for informing the user
419
+ * of the sent email as needed.
420
+ *
421
+ * @param options The password change options (email, connection, organization, etc.).
422
+ * @param storeOptions Optional options used to resolve the domain (resolver mode).
423
+ *
424
+ * @throws {ChangePasswordError} If there was an issue requesting the password change.
425
+ *
426
+ * @returns A promise resolving to the server's plain-text confirmation message.
427
+ */
428
+ async changePassword(options, storeOptions) {
429
+ const domain = await this.#options.resolveDomain(storeOptions);
430
+ return this.#options.getAuthClient(domain).database.changePassword(options);
431
+ }
432
+ };
433
+
386
434
  // src/server-client.ts
387
435
  var normalizeDomain = (value) => {
388
436
  const trimmed = value.trim();
@@ -408,6 +456,7 @@ var ServerClient = class {
408
456
  #authClient;
409
457
  #mfaClient;
410
458
  #passkeyClient;
459
+ #databaseClient;
411
460
  /**
412
461
  * The underlying `authClient` instance that can be used to interact with the Auth0 Authentication API.
413
462
  * Generally, you should prefer to use the higher-level methods exposed on the `ServerClient` instance.
@@ -455,6 +504,21 @@ var ServerClient = class {
455
504
  get passkey() {
456
505
  return this.#passkeyClient;
457
506
  }
507
+ /**
508
+ * The database client for self-service sign-up and password-change requests
509
+ * against an Auth0 database connection.
510
+ *
511
+ * Provides `signUp()` to register a user and `changePassword()` to request a
512
+ * password-reset email. Both are pure passthrough operations to the Auth0
513
+ * Authentication API — they never read or write the session/state store.
514
+ *
515
+ * Like `passkey`, this property is available in both static and resolver
516
+ * (multi-tenant) domain modes. In resolver mode, pass `storeOptions` so the
517
+ * request resolves the intended tenant.
518
+ */
519
+ get database() {
520
+ return this.#databaseClient;
521
+ }
458
522
  constructor(options) {
459
523
  this.#options = options;
460
524
  this.#stateStoreIdentifier = this.#options.stateIdentifier || "__a0_session";
@@ -504,6 +568,10 @@ var ServerClient = class {
504
568
  defaultScope: this.#options.authorizationParams?.scope,
505
569
  defaultAudience: this.#options.authorizationParams?.audience
506
570
  });
571
+ this.#databaseClient = new ServerDatabaseClient({
572
+ resolveDomain: (storeOptions) => this.#resolveDomain(storeOptions),
573
+ getAuthClient: (domain) => this.#getAuthClient(domain)
574
+ });
507
575
  }
508
576
  async #resolveDomain(storeOptions) {
509
577
  if (typeof this.#options.domain === "function") {
@@ -555,9 +623,16 @@ var ServerClient = class {
555
623
  }
556
624
  /**
557
625
  * Starts the interactive login process, and returns a URL to redirect the user-agent to to request authorization at Auth0.
626
+ *
627
+ * When `organization` is provided (per-login option, client-level default, or via
628
+ * `authorizationParams.organization`), it is forwarded to `/authorize` and remembered so the
629
+ * returned ID token's organization claim can be validated in `completeInteractiveLogin`.
630
+ *
558
631
  * @param options Optional options used to configure the interactive login process.
559
632
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
560
633
  *
634
+ * @throws {OrganizationValidationError} If the resolved `organization` is blank.
635
+ * @throws {InvalidConfigurationError} If `invitation` is provided without an `organization`.
561
636
  * @throws {BuildAuthorizationUrlError} If there was an issue when building the Authorization URL.
562
637
  *
563
638
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
@@ -568,6 +643,16 @@ var ServerClient = class {
568
643
  throw new MissingRequiredArgumentError("authorizationParams.redirect_uri");
569
644
  }
570
645
  const scope = ensureOpenIdScope(options?.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
646
+ const perLoginAuthParamsOrganization = typeof options?.authorizationParams?.organization === "string" ? options.authorizationParams.organization : void 0;
647
+ const clientAuthParamsOrganization = typeof this.#options.authorizationParams?.organization === "string" ? this.#options.authorizationParams.organization : void 0;
648
+ const resolvedOrganization = options?.organization ?? perLoginAuthParamsOrganization ?? this.#options.organization ?? clientAuthParamsOrganization;
649
+ if (resolvedOrganization !== void 0 && !resolvedOrganization.trim()) {
650
+ throw new OrganizationValidationError("organization must not be blank");
651
+ }
652
+ const hasInvitation = !!(options?.invitation || options?.authorizationParams?.invitation);
653
+ if (hasInvitation && !resolvedOrganization) {
654
+ throw new InvalidConfigurationError("organization is required when invitation is provided.");
655
+ }
571
656
  const domain = await this.#resolveDomain(storeOptions);
572
657
  const authClient = this.#getAuthClient(domain);
573
658
  const { codeVerifier, authorizationUrl } = await authClient.buildAuthorizationUrl({
@@ -575,7 +660,9 @@ var ServerClient = class {
575
660
  authorizationParams: {
576
661
  ...options?.authorizationParams,
577
662
  redirect_uri: redirectUri,
578
- scope
663
+ scope,
664
+ ...resolvedOrganization ? { organization: resolvedOrganization } : {},
665
+ ...options?.invitation ? { invitation: options.invitation } : {}
579
666
  }
580
667
  });
581
668
  const transactionState = {
@@ -583,6 +670,9 @@ var ServerClient = class {
583
670
  codeVerifier,
584
671
  domain
585
672
  };
673
+ if (resolvedOrganization) {
674
+ transactionState.organization = resolvedOrganization;
675
+ }
586
676
  if (options?.appState) {
587
677
  transactionState.appState = options.appState;
588
678
  }
@@ -597,6 +687,7 @@ var ServerClient = class {
597
687
  *
598
688
  * @throws {MissingTransactionError} When no transaction was found.
599
689
  * @throws {TokenByCodeError} If there was an issue requesting the access token.
690
+ * @throws {OrganizationValidationError} When an organization was requested at login and the returned ID token's organization claim is missing or does not match; nothing is persisted.
600
691
  * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
601
692
  *
602
693
  * @returns A promise resolving to an object, containing the original appState (if present) and the authorizationDetails (when RAR was used).
@@ -610,7 +701,8 @@ var ServerClient = class {
610
701
  const authClient = this.#getAuthClient(domain);
611
702
  const tokenEndpointResponse = await authClient.getTokenByCode(url, {
612
703
  // TransactionData.codeVerifier is optional only to accommodate magic-link transactions.
613
- codeVerifier: transactionData.codeVerifier
704
+ codeVerifier: transactionData.codeVerifier,
705
+ organization: transactionData.organization
614
706
  });
615
707
  await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
616
708
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
@@ -1145,6 +1237,47 @@ var ServerClient = class {
1145
1237
  loginHint: options.loginHint
1146
1238
  };
1147
1239
  }
1240
+ /**
1241
+ * Revokes the refresh token stored in the current session, or an explicitly supplied token.
1242
+ *
1243
+ * In resolver mode, revocation only occurs when the session domain matches the domain resolved
1244
+ * for the current request. If the domains differ (or the session has no stored domain), the call
1245
+ * returns without revoking to avoid sending a token to the wrong tenant. This guard applies even
1246
+ * when a token is passed explicitly via `options.token`.
1247
+ *
1248
+ * @param options Optionally supply a token to revoke instead of reading from the session.
1249
+ * @param storeOptions Optional options passed to the StateStore.
1250
+ *
1251
+ * @throws {MissingRequiredArgumentError} If `options.token` is an empty string.
1252
+ * @throws {MissingSessionError} If no refresh token is found in the session and none was provided.
1253
+ * @throws {TokenRevocationError} If the revocation request fails.
1254
+ */
1255
+ async revokeRefreshToken(options = {}, storeOptions) {
1256
+ if (options.token !== void 0 && options.token.length === 0) {
1257
+ throw new MissingRequiredArgumentError("options.token must not be an empty string.");
1258
+ }
1259
+ let refreshToken = options.token;
1260
+ const needsStateData = !refreshToken || this.#isResolverMode();
1261
+ const stateData = needsStateData ? await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions) : void 0;
1262
+ if (!refreshToken) {
1263
+ refreshToken = stateData?.refreshToken;
1264
+ }
1265
+ if (!refreshToken) {
1266
+ throw new MissingSessionError("Unable to revoke refresh token: no refresh token found in session.");
1267
+ }
1268
+ let authClient;
1269
+ if (this.#isResolverMode()) {
1270
+ const resolvedDomain = await this.#resolveDomain(storeOptions);
1271
+ const sessionDomain = stateData ? this.#getSessionDomain(stateData) : void 0;
1272
+ if (stateData && sessionDomain !== resolvedDomain) {
1273
+ return;
1274
+ }
1275
+ authClient = this.#getAuthClient(sessionDomain ?? resolvedDomain);
1276
+ } else {
1277
+ authClient = this.authClient;
1278
+ }
1279
+ await authClient.revokeToken({ token: refreshToken, tokenTypeHint: "refresh_token" });
1280
+ }
1148
1281
  /**
1149
1282
  * Logs the user out and returns a URL to redirect the user-agent to after they log out.
1150
1283
  * @param options Options used to configure the logout process.
@@ -1153,17 +1286,26 @@ var ServerClient = class {
1153
1286
  */
1154
1287
  async logout(options, storeOptions) {
1155
1288
  if (!this.#isResolverMode()) {
1289
+ try {
1290
+ await this.revokeRefreshToken({}, storeOptions);
1291
+ } catch {
1292
+ }
1156
1293
  await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
1157
1294
  return this.authClient.buildLogoutUrl(options);
1158
1295
  }
1159
1296
  const resolvedDomain = await this.#resolveDomain(storeOptions);
1160
1297
  const authClient = this.#getAuthClient(resolvedDomain);
1161
1298
  const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
1162
- const sessionDomain = stateData ? this.#getSessionDomain(stateData) : void 0;
1163
1299
  if (!stateData) {
1164
1300
  return authClient.buildLogoutUrl(options);
1165
1301
  }
1166
- if (sessionDomain && sessionDomain === resolvedDomain) {
1302
+ const sessionDomain = this.#getSessionDomain(stateData);
1303
+ const domainMatches = sessionDomain === resolvedDomain;
1304
+ if (domainMatches) {
1305
+ try {
1306
+ await this.revokeRefreshToken({}, storeOptions);
1307
+ } catch {
1308
+ }
1167
1309
  await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
1168
1310
  }
1169
1311
  return authClient.buildLogoutUrl(options);
@@ -1381,7 +1523,7 @@ var AbstractTransactionStore = class extends AbstractStore {
1381
1523
  };
1382
1524
 
1383
1525
  // src/index.ts
1384
- import { TokenExchangeError, MissingClientAuthError } from "@auth0/auth0-auth-js";
1526
+ import { TokenExchangeError, TokenRevocationError, MissingClientAuthError, OrganizationValidationError as OrganizationValidationError3 } from "@auth0/auth0-auth-js";
1385
1527
 
1386
1528
  // src/store/cookie-transaction-store.ts
1387
1529
  var CookieTransactionStore = class extends AbstractTransactionStore {
@@ -1591,12 +1733,16 @@ import {
1591
1733
  PasskeyRegisterError,
1592
1734
  PasskeyChallengeError,
1593
1735
  PasskeyGetTokenError,
1594
- OrganizationValidationError
1736
+ OrganizationValidationError as OrganizationValidationError2
1595
1737
  } from "@auth0/auth0-auth-js";
1738
+
1739
+ // src/database/index.ts
1740
+ import { SignUpError, ChangePasswordError } from "@auth0/auth0-auth-js";
1596
1741
  export {
1597
1742
  AbstractStateStore,
1598
1743
  AbstractTransactionStore,
1599
1744
  BackchannelLogoutError,
1745
+ ChangePasswordError,
1600
1746
  CookieTransactionStore,
1601
1747
  InvalidConfigurationError,
1602
1748
  IssuerValidationError,
@@ -1608,18 +1754,21 @@ export {
1608
1754
  MissingRequiredArgumentError,
1609
1755
  MissingSessionError,
1610
1756
  MissingTransactionError,
1611
- OrganizationValidationError,
1757
+ OrganizationValidationError3 as OrganizationValidationError,
1612
1758
  PasskeyChallengeError,
1613
1759
  PasskeyGetTokenError,
1614
1760
  PasskeyRegisterError,
1615
1761
  ServerClient,
1762
+ ServerDatabaseClient,
1616
1763
  ServerMfaClient,
1617
1764
  ServerPasskeyClient,
1618
1765
  SessionExpiredError,
1766
+ SignUpError,
1619
1767
  StartLinkUserError,
1620
1768
  StatefulStateStore,
1621
1769
  StatelessStateStore,
1622
1770
  TokenExchangeError,
1771
+ TokenRevocationError,
1623
1772
  isMfaRequiredError
1624
1773
  };
1625
1774
  //# sourceMappingURL=index.js.map