@auth0/auth0-server-js 1.3.0 → 1.5.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.cjs CHANGED
@@ -25,13 +25,20 @@ __export(index_exports, {
25
25
  BackchannelLogoutError: () => BackchannelLogoutError,
26
26
  CookieTransactionStore: () => CookieTransactionStore,
27
27
  InvalidConfigurationError: () => InvalidConfigurationError,
28
+ IssuerValidationError: () => IssuerValidationError,
29
+ MfaChallengeError: () => import_auth0_auth_js2.MfaChallengeError,
30
+ MfaEnrollmentError: () => import_auth0_auth_js2.MfaEnrollmentError,
31
+ MfaListAuthenticatorsError: () => import_auth0_auth_js2.MfaListAuthenticatorsError,
32
+ MfaVerifyError: () => import_auth0_auth_js2.MfaVerifyError,
28
33
  MissingRequiredArgumentError: () => MissingRequiredArgumentError,
29
34
  MissingSessionError: () => MissingSessionError,
30
35
  MissingTransactionError: () => MissingTransactionError,
31
36
  ServerClient: () => ServerClient,
37
+ ServerMfaClient: () => ServerMfaClient,
32
38
  StartLinkUserError: () => StartLinkUserError,
33
39
  StatefulStateStore: () => StatefulStateStore,
34
- StatelessStateStore: () => StatelessStateStore
40
+ StatelessStateStore: () => StatelessStateStore,
41
+ isMfaRequiredError: () => import_auth0_auth_js2.isMfaRequiredError
35
42
  });
36
43
  module.exports = __toCommonJS(index_exports);
37
44
 
@@ -78,6 +85,13 @@ var InvalidConfigurationError = class extends Error {
78
85
  this.name = "InvalidConfigurationError";
79
86
  }
80
87
  };
88
+ var IssuerValidationError = class extends Error {
89
+ code = "issuer_validation_error";
90
+ constructor(message) {
91
+ super(message);
92
+ this.name = "IssuerValidationError";
93
+ }
94
+ };
81
95
 
82
96
  // src/state/utils.ts
83
97
  var createUpdatedTokenSet = (audience, response) => ({
@@ -86,7 +100,18 @@ var createUpdatedTokenSet = (audience, response) => ({
86
100
  scope: response.scope,
87
101
  expiresAt: response.expiresAt
88
102
  });
89
- function updateStateData(audience, stateData, tokenEndpointResponse) {
103
+ function updateStateData(audience, stateData, tokenEndpointResponse, context) {
104
+ if (stateData && tokenEndpointResponse.claims) {
105
+ const newSub = tokenEndpointResponse.claims.sub;
106
+ const newIss = tokenEndpointResponse.claims.iss;
107
+ const existingSub = stateData.user?.sub;
108
+ const existingIss = stateData.user?.iss;
109
+ const subMismatch = newSub !== void 0 && existingSub !== void 0 && newSub !== existingSub;
110
+ const issMismatch = newIss !== void 0 && existingIss !== void 0 && newIss !== existingIss;
111
+ if (subMismatch || issMismatch) {
112
+ stateData = void 0;
113
+ }
114
+ }
90
115
  if (stateData) {
91
116
  const isNewTokenSet = !stateData.tokenSets.some(
92
117
  (tokenSet) => tokenSet.audience === audience && tokenSet.scope === tokenEndpointResponse.scope
@@ -98,7 +123,8 @@ function updateStateData(audience, stateData, tokenEndpointResponse) {
98
123
  ...stateData,
99
124
  idToken: tokenEndpointResponse.idToken ?? stateData.idToken,
100
125
  refreshToken: tokenEndpointResponse.refreshToken ?? stateData.refreshToken,
101
- tokenSets
126
+ tokenSets,
127
+ domain: context?.domain ?? stateData.domain
102
128
  };
103
129
  } else {
104
130
  const user = tokenEndpointResponse.claims;
@@ -106,9 +132,8 @@ function updateStateData(audience, stateData, tokenEndpointResponse) {
106
132
  user,
107
133
  idToken: tokenEndpointResponse.idToken,
108
134
  refreshToken: tokenEndpointResponse.refreshToken,
109
- tokenSets: [
110
- createUpdatedTokenSet(audience, tokenEndpointResponse)
111
- ],
135
+ tokenSets: [createUpdatedTokenSet(audience, tokenEndpointResponse)],
136
+ domain: context?.domain,
112
137
  internal: {
113
138
  sid: user?.sid,
114
139
  createdAt: Math.floor(Date.now() / 1e3)
@@ -153,6 +178,9 @@ var compareScopes = (scopes, requiredScopes) => {
153
178
  return requiredScopesArray.every((scope) => scopesSet.has(scope));
154
179
  };
155
180
 
181
+ // src/server-client.ts
182
+ var import_jose = require("jose");
183
+
156
184
  // src/telemetry.ts
157
185
  function getTelemetryConfig(config) {
158
186
  if (config?.enabled === false) {
@@ -161,13 +189,106 @@ function getTelemetryConfig(config) {
161
189
  return {
162
190
  enabled: true,
163
191
  name: config?.name ?? "@auth0/auth0-server-js",
164
- version: config?.version ?? "1.3.0"
192
+ version: config?.version ?? "1.5.0"
165
193
  };
166
194
  }
167
195
 
196
+ // src/mfa/server-mfa-client.ts
197
+ var ServerMfaClient = class {
198
+ #options;
199
+ /**
200
+ * @internal
201
+ */
202
+ constructor(options) {
203
+ this.#options = options;
204
+ }
205
+ /**
206
+ * Lists all MFA authenticators enrolled by the user.
207
+ *
208
+ * @param options - Options for listing authenticators
209
+ * @returns Promise resolving to an array of enrolled authenticators
210
+ * @throws {MfaListAuthenticatorsError} When the request fails
211
+ */
212
+ async listAuthenticators(options) {
213
+ return this.#options.authClient.mfa.listAuthenticators(options);
214
+ }
215
+ /**
216
+ * Enrolls a new MFA authenticator for the user.
217
+ *
218
+ * @param options - Enrollment options
219
+ * @returns Promise resolving to enrollment response with authenticator details
220
+ * @throws {MfaEnrollmentError} When enrollment fails
221
+ */
222
+ async enrollAuthenticator(options) {
223
+ return this.#options.authClient.mfa.enrollAuthenticator(options);
224
+ }
225
+ /**
226
+ * Initiates an MFA challenge for user verification.
227
+ *
228
+ * @param options - Challenge options
229
+ * @returns Promise resolving to challenge response with challenge details
230
+ * @throws {MfaChallengeError} When the challenge fails
231
+ */
232
+ async challengeAuthenticator(options) {
233
+ return this.#options.authClient.mfa.challengeAuthenticator(options);
234
+ }
235
+ /**
236
+ * Verifies an MFA challenge and completes the authentication flow.
237
+ *
238
+ * Exchanges the MFA token and verification code for access, ID, and refresh tokens,
239
+ * then saves them into the user's session automatically.
240
+ *
241
+ * @param options - The MFA token, factor type (otp / oob / recovery-code), and the code to verify
242
+ * @param storeOptions - Optional options forwarded to the session store. Can be omitted when
243
+ * using the built-in stores; required if your custom store needs extra context (e.g. a request object).
244
+ * @returns The tokens returned by Auth0 after successful verification
245
+ * @throws {MfaVerifyError} When verification fails (e.g. invalid token, wrong code)
246
+ */
247
+ async verify(options, storeOptions) {
248
+ const tokenResponse = await this.#options.authClient.mfa.verify(options);
249
+ const audience = options.audience ?? this.#options.defaultAudience;
250
+ const existingStateData = await this.#options.stateStore.get(
251
+ this.#options.stateStoreIdentifier,
252
+ storeOptions
253
+ );
254
+ const updatedStateData = updateStateData(audience, existingStateData, tokenResponse, {
255
+ domain: this.#options.domain
256
+ });
257
+ await this.#options.stateStore.set(
258
+ this.#options.stateStoreIdentifier,
259
+ updatedStateData,
260
+ true,
261
+ storeOptions
262
+ );
263
+ const result = {
264
+ accessToken: tokenResponse.accessToken,
265
+ tokenType: tokenResponse.tokenType ?? "bearer",
266
+ expiresAt: tokenResponse.expiresAt,
267
+ scope: tokenResponse.scope
268
+ };
269
+ if (tokenResponse.idToken) result.idToken = tokenResponse.idToken;
270
+ if (tokenResponse.refreshToken) result.refreshToken = tokenResponse.refreshToken;
271
+ if (tokenResponse.recoveryCode) result.recoveryCode = tokenResponse.recoveryCode;
272
+ return result;
273
+ }
274
+ };
275
+
168
276
  // src/server-client.ts
169
277
  var DEFAULT_SCOPES = "openid profile email offline_access";
170
- function ensureOpenIdScope(scope) {
278
+ var normalizeDomain = (value) => {
279
+ const trimmed = value.trim();
280
+ const parsed = trimmed.startsWith("http") ? new URL(trimmed) : new URL(`https://${trimmed}`);
281
+ return parsed.host.toLowerCase();
282
+ };
283
+ var decodeIssuer = (token) => {
284
+ try {
285
+ const { iss } = (0, import_jose.decodeJwt)(token);
286
+ return typeof iss === "string" ? iss : void 0;
287
+ } catch {
288
+ return void 0;
289
+ }
290
+ };
291
+ var ensureOpenIdScope = (scope) => {
171
292
  if (!scope) {
172
293
  return DEFAULT_SCOPES;
173
294
  }
@@ -176,20 +297,51 @@ function ensureOpenIdScope(scope) {
176
297
  scopes.unshift("openid");
177
298
  }
178
299
  return scopes.join(" ");
179
- }
300
+ };
180
301
  var ServerClient = class {
181
302
  #options;
182
303
  #transactionStore;
183
304
  #transactionStoreIdentifier;
184
305
  #stateStore;
185
306
  #stateStoreIdentifier;
307
+ #authClientOptions;
308
+ #staticDomain;
309
+ #authClient;
310
+ #mfaClient;
186
311
  /**
187
312
  * The underlying `authClient` instance that can be used to interact with the Auth0 Authentication API.
188
313
  * Generally, you should prefer to use the higher-level methods exposed on the `ServerClient` instance.
189
- *
314
+ *
315
+ * This property can only be used when `domain` is configured as a static string.
316
+ * In resolver mode (`domain` as a function), the SDK resolves the domain per request,
317
+ * so use `ServerClient` methods instead.
318
+ *
190
319
  * Important: the methods exposed on the `authClient` instance do not handle any session or state management.
191
320
  */
192
- authClient;
321
+ get authClient() {
322
+ if (!this.#authClient) {
323
+ throw new InvalidConfigurationError("authClient is only available when using a static domain configuration.");
324
+ }
325
+ return this.#authClient;
326
+ }
327
+ /**
328
+ * The MFA client for managing multi-factor authentication operations.
329
+ *
330
+ * Provides methods to list, enroll, and challenge MFA authenticators,
331
+ * as well as verify MFA challenges to complete authentication.
332
+ *
333
+ * The `verify` method integrates with the session state store, persisting tokens
334
+ * and user data after successful MFA verification.
335
+ *
336
+ * This property can only be used when `domain` is configured as a static string.
337
+ * In resolver mode (`domain` as a function), MFA is not supported.
338
+ */
339
+ get mfa() {
340
+ if (!this.#mfaClient) {
341
+ throw new InvalidConfigurationError("mfa is only available when using a static domain configuration.");
342
+ }
343
+ return this.#mfaClient;
344
+ }
193
345
  constructor(options) {
194
346
  this.#options = options;
195
347
  this.#stateStoreIdentifier = this.#options.stateIdentifier || "__a0_session";
@@ -202,18 +354,84 @@ var ServerClient = class {
202
354
  if (!this.#options.transactionStore) {
203
355
  throw new MissingRequiredArgumentError("transactionStore");
204
356
  }
205
- this.authClient = new import_auth0_auth_js.AuthClient({
206
- domain: this.#options.domain,
357
+ if (typeof this.#options.domain !== "string" && typeof this.#options.domain !== "function") {
358
+ throw new InvalidConfigurationError("domain must be a string or resolver function");
359
+ }
360
+ this.#authClientOptions = {
207
361
  clientId: this.#options.clientId,
208
362
  clientSecret: this.#options.clientSecret,
209
363
  clientAssertionSigningKey: this.#options.clientAssertionSigningKey,
210
364
  clientAssertionSigningAlg: this.#options.clientAssertionSigningAlg,
211
365
  authorizationParams: this.#options.authorizationParams,
366
+ discoveryCache: this.#options.discoveryCache,
212
367
  customFetch: this.#options.customFetch,
213
- useMtls: this.#options.useMtls,
368
+ useMtls: this.#options.useMtls
369
+ };
370
+ if (typeof this.#options.domain === "string") {
371
+ const domain = normalizeDomain(this.#options.domain);
372
+ this.#staticDomain = domain;
373
+ this.#authClient = new import_auth0_auth_js.AuthClient({
374
+ domain,
375
+ ...this.#authClientOptions,
376
+ telemetry: getTelemetryConfig(this.#options.telemetry)
377
+ });
378
+ this.#mfaClient = new ServerMfaClient({
379
+ authClient: this.#authClient,
380
+ domain,
381
+ stateStore: this.#stateStore,
382
+ stateStoreIdentifier: this.#stateStoreIdentifier,
383
+ defaultAudience: this.#options.authorizationParams?.audience ?? "default"
384
+ });
385
+ }
386
+ }
387
+ async #resolveDomain(storeOptions) {
388
+ if (typeof this.#options.domain === "function") {
389
+ const resolved = await this.#options.domain(storeOptions);
390
+ if (typeof resolved !== "string" || resolved.trim().length === 0) {
391
+ throw new InvalidConfigurationError("domainResolver returned no domain");
392
+ }
393
+ return normalizeDomain(resolved);
394
+ }
395
+ return normalizeDomain(this.#options.domain);
396
+ }
397
+ #createAuthClient(domain) {
398
+ return new import_auth0_auth_js.AuthClient({
399
+ domain,
400
+ ...this.#authClientOptions,
214
401
  telemetry: getTelemetryConfig(this.#options.telemetry)
215
402
  });
216
403
  }
404
+ #getAuthClient(domain) {
405
+ const normalizedDomain = normalizeDomain(domain);
406
+ if (this.#authClient && this.#staticDomain === normalizedDomain) {
407
+ return this.#authClient;
408
+ }
409
+ return this.#createAuthClient(normalizedDomain);
410
+ }
411
+ #getSessionDomain(stateData) {
412
+ if (stateData.domain) {
413
+ return normalizeDomain(stateData.domain);
414
+ }
415
+ if (this.#staticDomain) {
416
+ return this.#staticDomain;
417
+ }
418
+ const issuerFromClaims = stateData.user?.iss;
419
+ if (typeof issuerFromClaims === "string" && issuerFromClaims.trim().length > 0) {
420
+ return normalizeDomain(issuerFromClaims);
421
+ }
422
+ return;
423
+ }
424
+ #isResolverMode() {
425
+ return typeof this.#options.domain === "function";
426
+ }
427
+ async #isSessionForCurrentDomain(stateData, storeOptions) {
428
+ const sessionDomain = this.#getSessionDomain(stateData);
429
+ if (!sessionDomain) {
430
+ return false;
431
+ }
432
+ const resolvedDomain = await this.#resolveDomain(storeOptions);
433
+ return sessionDomain === resolvedDomain;
434
+ }
217
435
  /**
218
436
  * Starts the interactive login process, and returns a URL to redirect the user-agent to to request authorization at Auth0.
219
437
  * @param options Optional options used to configure the interactive login process.
@@ -229,7 +447,9 @@ var ServerClient = class {
229
447
  throw new MissingRequiredArgumentError("authorizationParams.redirect_uri");
230
448
  }
231
449
  const scope = ensureOpenIdScope(options?.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
232
- const { codeVerifier, authorizationUrl } = await this.authClient.buildAuthorizationUrl({
450
+ const domain = await this.#resolveDomain(storeOptions);
451
+ const authClient = this.#getAuthClient(domain);
452
+ const { codeVerifier, authorizationUrl } = await authClient.buildAuthorizationUrl({
233
453
  pushedAuthorizationRequests: options?.pushedAuthorizationRequests,
234
454
  authorizationParams: {
235
455
  ...options?.authorizationParams,
@@ -239,7 +459,8 @@ var ServerClient = class {
239
459
  });
240
460
  const transactionState = {
241
461
  audience: options?.authorizationParams?.audience ?? this.#options.authorizationParams?.audience,
242
- codeVerifier
462
+ codeVerifier,
463
+ domain
243
464
  };
244
465
  if (options?.appState) {
245
466
  transactionState.appState = options.appState;
@@ -263,11 +484,15 @@ var ServerClient = class {
263
484
  if (!transactionData) {
264
485
  throw new MissingTransactionError();
265
486
  }
266
- const tokenEndpointResponse = await this.authClient.getTokenByCode(url, {
487
+ const domain = transactionData.domain ?? await this.#resolveDomain(storeOptions);
488
+ const authClient = this.#getAuthClient(domain);
489
+ const tokenEndpointResponse = await authClient.getTokenByCode(url, {
267
490
  codeVerifier: transactionData.codeVerifier
268
491
  });
269
492
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
270
- const stateData = updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse);
493
+ const stateData = updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse, {
494
+ domain
495
+ });
271
496
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
272
497
  await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
273
498
  return { appState: transactionData.appState, authorizationDetails: tokenEndpointResponse.authorizationDetails };
@@ -289,7 +514,15 @@ var ServerClient = class {
289
514
  "Unable to start the user linking process without a logged in user. Ensure to login using the SDK before starting the user linking process."
290
515
  );
291
516
  }
292
- const { linkUserUrl, codeVerifier } = await this.authClient.buildLinkUserUrl({
517
+ if (this.#isResolverMode()) {
518
+ const isCurrentDomain = await this.#isSessionForCurrentDomain(stateData, storeOptions);
519
+ if (!isCurrentDomain) {
520
+ throw new MissingSessionError("Session domain does not match the current domain.");
521
+ }
522
+ }
523
+ const domain = this.#getSessionDomain(stateData);
524
+ const authClient = this.#getAuthClient(domain);
525
+ const { linkUserUrl, codeVerifier } = await authClient.buildLinkUserUrl({
293
526
  connection: options.connection,
294
527
  connectionScope: options.connectionScope,
295
528
  idToken: stateData.idToken,
@@ -297,7 +530,8 @@ var ServerClient = class {
297
530
  });
298
531
  const transactionState = {
299
532
  audience: options?.authorizationParams?.audience ?? this.#options.authorizationParams?.audience,
300
- codeVerifier
533
+ codeVerifier,
534
+ domain
301
535
  };
302
536
  if (options?.appState) {
303
537
  transactionState.appState = options.appState;
@@ -339,14 +573,23 @@ var ServerClient = class {
339
573
  "Unable to start the user unlinking process without a logged in user. Ensure to login using the SDK before starting the user unlinking process."
340
574
  );
341
575
  }
342
- const { unlinkUserUrl, codeVerifier } = await this.authClient.buildUnlinkUserUrl({
576
+ if (this.#isResolverMode()) {
577
+ const isCurrentDomain = await this.#isSessionForCurrentDomain(stateData, storeOptions);
578
+ if (!isCurrentDomain) {
579
+ throw new MissingSessionError("Session domain does not match the current domain.");
580
+ }
581
+ }
582
+ const domain = this.#getSessionDomain(stateData);
583
+ const authClient = this.#getAuthClient(domain);
584
+ const { unlinkUserUrl, codeVerifier } = await authClient.buildUnlinkUserUrl({
343
585
  connection: options.connection,
344
586
  idToken: stateData.idToken,
345
587
  authorizationParams: options.authorizationParams
346
588
  });
347
589
  const transactionState = {
348
590
  audience: options?.authorizationParams?.audience ?? this.#options.authorizationParams?.audience,
349
- codeVerifier
591
+ codeVerifier,
592
+ domain
350
593
  };
351
594
  if (options?.appState) {
352
595
  transactionState.appState = options.appState;
@@ -385,7 +628,9 @@ var ServerClient = class {
385
628
  */
386
629
  async loginBackchannel(options, storeOptions) {
387
630
  const scope = ensureOpenIdScope(options.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
388
- const tokenEndpointResponse = await this.authClient.backchannelAuthentication({
631
+ const domain = await this.#resolveDomain(storeOptions);
632
+ const authClient = this.#getAuthClient(domain);
633
+ const tokenEndpointResponse = await authClient.backchannelAuthentication({
389
634
  bindingMessage: options.bindingMessage,
390
635
  loginHint: options.loginHint,
391
636
  authorizationParams: {
@@ -397,7 +642,8 @@ var ServerClient = class {
397
642
  const stateData = updateStateData(
398
643
  this.#options.authorizationParams?.audience ?? "default",
399
644
  existingStateData,
400
- tokenEndpointResponse
645
+ tokenEndpointResponse,
646
+ { domain }
401
647
  );
402
648
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
403
649
  return {
@@ -411,16 +657,31 @@ var ServerClient = class {
411
657
  */
412
658
  async getUser(storeOptions) {
413
659
  const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
414
- return stateData?.user;
660
+ if (!stateData) {
661
+ return;
662
+ }
663
+ if (this.#isResolverMode()) {
664
+ const isCurrentDomain = await this.#isSessionForCurrentDomain(stateData, storeOptions);
665
+ if (!isCurrentDomain) {
666
+ return;
667
+ }
668
+ }
669
+ return stateData.user;
415
670
  }
416
671
  /**
417
672
  * Retrieve the user session from the store, or undefined if no session found.
418
673
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
419
- * @returns The sessionm or undefined if no session found in the store.
674
+ * @returns The session or undefined if no session found in the store.
420
675
  */
421
676
  async getSession(storeOptions) {
422
677
  const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
423
678
  if (stateData) {
679
+ if (this.#isResolverMode()) {
680
+ const isCurrentDomain = await this.#isSessionForCurrentDomain(stateData, storeOptions);
681
+ if (!isCurrentDomain) {
682
+ return;
683
+ }
684
+ }
424
685
  const { internal, ...sessionData } = stateData;
425
686
  return sessionData;
426
687
  }
@@ -428,24 +689,29 @@ var ServerClient = class {
428
689
  /**
429
690
  * Retrieves the access token from the store, or calls Auth0 when the access token is expired and a refresh token is available in the store.
430
691
  * Also updates the store when a new token was retrieved from Auth0.
431
- *
432
- * @param options Optional options for requesting specific audience/scope.
433
692
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
434
693
  *
435
- * @throws {TokenByRefreshTokenError} If the refresh token was not found or there was an issue requesting the access token.
694
+ * @throws {TokenByRefreshTokenError} If the refresh token was not found or there was an issue requesting the access token. When the cause is `mfa_required`, use `isMfaRequiredError(error)` to narrow the error and read `cause.mfa_token`.
436
695
  *
437
696
  * @returns The Token Set, containing the access token, as well as additional information.
438
697
  */
439
- async getAccessToken(tokenOptionsOrStoreOptions, storeOptions) {
440
- const hasTokenOptions = (
441
- // If second arg exists, first arg must be GetAccessTokenOptions
442
- storeOptions !== void 0 || // OR if first arg has audience/scope properties
443
- tokenOptionsOrStoreOptions && typeof tokenOptionsOrStoreOptions === "object" && ("audience" in tokenOptionsOrStoreOptions || "scope" in tokenOptionsOrStoreOptions)
444
- );
445
- const [resolvedOptions, resolvedStoreOptions] = hasTokenOptions ? [tokenOptionsOrStoreOptions, storeOptions] : [void 0, tokenOptionsOrStoreOptions];
446
- const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, resolvedStoreOptions);
447
- const audience = resolvedOptions?.audience ?? this.#options.authorizationParams?.audience ?? "default";
448
- const scope = resolvedOptions?.scope ?? this.#options.authorizationParams?.scope;
698
+ async getAccessToken(storeOptions) {
699
+ const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
700
+ const audience = this.#options.authorizationParams?.audience ?? "default";
701
+ const scope = this.#options.authorizationParams?.scope;
702
+ const sessionDomain = stateData ? this.#getSessionDomain(stateData) : this.#staticDomain;
703
+ if (this.#isResolverMode()) {
704
+ if (!stateData) {
705
+ throw new MissingSessionError("Unable to retrieve access token without a logged in user.");
706
+ }
707
+ if (!sessionDomain) {
708
+ throw new MissingSessionError("Session domain does not match the current domain.");
709
+ }
710
+ const resolvedDomain = await this.#resolveDomain(storeOptions);
711
+ if (sessionDomain !== resolvedDomain) {
712
+ throw new MissingSessionError("Session domain does not match the current domain.");
713
+ }
714
+ }
449
715
  const tokenSet = stateData?.tokenSets.find(
450
716
  (tokenSet2) => tokenSet2.audience === audience && (!scope || compareScopes(tokenSet2.scope, scope))
451
717
  );
@@ -457,14 +723,15 @@ var ServerClient = class {
457
723
  "The access token has expired and a refresh token was not provided. The user needs to re-authenticate."
458
724
  );
459
725
  }
460
- const tokenByRefreshTokenOptions = {
461
- refreshToken: stateData.refreshToken,
462
- ...hasTokenOptions && { audience, scope }
463
- };
464
- const tokenEndpointResponse = await this.authClient.getTokenByRefreshToken(tokenByRefreshTokenOptions);
465
- const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, resolvedStoreOptions);
466
- const updatedStateData = updateStateData(audience, existingStateData, tokenEndpointResponse);
467
- await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, resolvedStoreOptions);
726
+ const domainForSession = sessionDomain;
727
+ const tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenByRefreshToken({
728
+ refreshToken: stateData.refreshToken
729
+ });
730
+ const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
731
+ const updatedStateData = updateStateData(audience, existingStateData, tokenEndpointResponse, {
732
+ domain: domainForSession
733
+ });
734
+ await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, storeOptions);
468
735
  return {
469
736
  accessToken: tokenEndpointResponse.accessToken,
470
737
  scope: tokenEndpointResponse.scope,
@@ -489,6 +756,19 @@ var ServerClient = class {
489
756
  */
490
757
  async getAccessTokenForConnection(options, storeOptions) {
491
758
  const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
759
+ const sessionDomain = stateData ? this.#getSessionDomain(stateData) : this.#staticDomain;
760
+ if (this.#isResolverMode()) {
761
+ if (!stateData) {
762
+ throw new MissingSessionError("Unable to retrieve an access token for a connection without a logged in user.");
763
+ }
764
+ if (!sessionDomain) {
765
+ throw new MissingSessionError("Session domain does not match the current domain.");
766
+ }
767
+ const resolvedDomain = await this.#resolveDomain(storeOptions);
768
+ if (sessionDomain !== resolvedDomain) {
769
+ throw new MissingSessionError("Session domain does not match the current domain.");
770
+ }
771
+ }
492
772
  const connectionTokenSet = stateData?.connectionTokenSets?.find(
493
773
  (tokenSet) => tokenSet.connection === options.connection
494
774
  );
@@ -500,12 +780,20 @@ var ServerClient = class {
500
780
  "A refresh token was not found but is required to be able to retrieve an access token for a connection."
501
781
  );
502
782
  }
503
- const tokenEndpointResponse = await this.authClient.getTokenForConnection({
783
+ const domainForSession = sessionDomain;
784
+ const tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenForConnection({
504
785
  connection: options.connection,
505
786
  loginHint: options.loginHint,
506
787
  refreshToken: stateData.refreshToken
507
788
  });
508
- const updatedStateData = updateStateDataForConnectionTokenSet(options, stateData, tokenEndpointResponse);
789
+ const updatedStateData = updateStateDataForConnectionTokenSet(
790
+ options,
791
+ {
792
+ ...stateData,
793
+ domain: stateData.domain ?? domainForSession
794
+ },
795
+ tokenEndpointResponse
796
+ );
509
797
  await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, storeOptions);
510
798
  return {
511
799
  accessToken: tokenEndpointResponse.accessToken,
@@ -522,8 +810,21 @@ var ServerClient = class {
522
810
  * @returns {URL}
523
811
  */
524
812
  async logout(options, storeOptions) {
525
- await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
526
- return this.authClient.buildLogoutUrl(options);
813
+ if (!this.#isResolverMode()) {
814
+ await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
815
+ return this.authClient.buildLogoutUrl(options);
816
+ }
817
+ const resolvedDomain = await this.#resolveDomain(storeOptions);
818
+ const authClient = this.#getAuthClient(resolvedDomain);
819
+ const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
820
+ const sessionDomain = stateData ? this.#getSessionDomain(stateData) : void 0;
821
+ if (!stateData) {
822
+ return authClient.buildLogoutUrl(options);
823
+ }
824
+ if (sessionDomain && sessionDomain === resolvedDomain) {
825
+ await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
826
+ }
827
+ return authClient.buildLogoutUrl(options);
527
828
  }
528
829
  /**
529
830
  * Handles the backchannel logout process by verifying the logout token and deleting the session from the store if the logout token was considered valid.
@@ -537,13 +838,28 @@ var ServerClient = class {
537
838
  if (!logoutToken) {
538
839
  throw new BackchannelLogoutError("Missing Logout Token");
539
840
  }
540
- const logoutTokenClaims = await this.authClient.verifyLogoutToken({ logoutToken });
541
- await this.#stateStore.deleteByLogoutToken(logoutTokenClaims, storeOptions);
841
+ if (!this.#isResolverMode()) {
842
+ const logoutTokenClaims2 = await this.authClient.verifyLogoutToken({ logoutToken });
843
+ await this.#stateStore.deleteByLogoutToken(logoutTokenClaims2, storeOptions);
844
+ return;
845
+ }
846
+ const issuer = decodeIssuer(logoutToken);
847
+ if (!issuer) {
848
+ throw new BackchannelLogoutError("Logout token is missing an issuer");
849
+ }
850
+ const resolvedDomain = await this.#resolveDomain(storeOptions);
851
+ const domain = normalizeDomain(issuer);
852
+ if (domain !== resolvedDomain) {
853
+ throw new BackchannelLogoutError("Logout token issuer does not match the resolved domain");
854
+ }
855
+ const authClient = this.#getAuthClient(domain);
856
+ const logoutTokenClaims = await authClient.verifyLogoutToken({ logoutToken });
857
+ await this.#stateStore.deleteByLogoutToken({ ...logoutTokenClaims, iss: issuer }, storeOptions);
542
858
  }
543
859
  };
544
860
 
545
861
  // src/encryption/index.ts
546
- var import_jose = require("jose");
862
+ var import_jose2 = require("jose");
547
863
  var ENC = "A256CBC-HS512";
548
864
  var ALG = "dir";
549
865
  var DIGEST = "SHA-256";
@@ -551,7 +867,7 @@ var BIT_LENGTH = 512;
551
867
  var HKDF_INFO = "derived cookie encryption secret";
552
868
  var encoder;
553
869
  function isDecryptionError(e) {
554
- return e instanceof import_jose.errors.JWEDecryptionFailed || e instanceof import_jose.errors.JWEInvalid;
870
+ return e instanceof import_jose2.errors.JWEDecryptionFailed || e instanceof import_jose2.errors.JWEInvalid;
555
871
  }
556
872
  async function deriveEncryptionSecret(secret, salt, kid) {
557
873
  encoder ||= new TextEncoder();
@@ -572,7 +888,7 @@ async function deriveEncryptionSecret(secret, salt, kid) {
572
888
  async function _encrypt(payload, secret, salt, expiration) {
573
889
  const kid = crypto.randomUUID();
574
890
  const encryptionSecret = await deriveEncryptionSecret(secret, salt, kid);
575
- return await new import_jose.EncryptJWT(payload).setProtectedHeader({ enc: ENC, alg: ALG, kid }).setExpirationTime(expiration).encrypt(encryptionSecret);
891
+ return await new import_jose2.EncryptJWT(payload).setProtectedHeader({ enc: ENC, alg: ALG, kid }).setExpirationTime(expiration).encrypt(encryptionSecret);
576
892
  }
577
893
  async function encrypt(payload, secret, salt, expiration) {
578
894
  if (typeof secret === "string") {
@@ -586,7 +902,7 @@ async function encrypt(payload, secret, salt, expiration) {
586
902
  }
587
903
  }
588
904
  async function _decrypt(value, secret, salt) {
589
- const res = await (0, import_jose.jwtDecrypt)(
905
+ const res = await (0, import_jose2.jwtDecrypt)(
590
906
  value,
591
907
  async (protectedHeader) => {
592
908
  if (!protectedHeader.kid) {
@@ -856,6 +1172,9 @@ var StatelessStateStore = class extends AbstractSessionStore {
856
1172
  };
857
1173
  }
858
1174
  };
1175
+
1176
+ // src/mfa/index.ts
1177
+ var import_auth0_auth_js2 = require("@auth0/auth0-auth-js");
859
1178
  // Annotate the CommonJS export names for ESM import in node:
860
1179
  0 && (module.exports = {
861
1180
  AbstractStateStore,
@@ -863,12 +1182,19 @@ var StatelessStateStore = class extends AbstractSessionStore {
863
1182
  BackchannelLogoutError,
864
1183
  CookieTransactionStore,
865
1184
  InvalidConfigurationError,
1185
+ IssuerValidationError,
1186
+ MfaChallengeError,
1187
+ MfaEnrollmentError,
1188
+ MfaListAuthenticatorsError,
1189
+ MfaVerifyError,
866
1190
  MissingRequiredArgumentError,
867
1191
  MissingSessionError,
868
1192
  MissingTransactionError,
869
1193
  ServerClient,
1194
+ ServerMfaClient,
870
1195
  StartLinkUserError,
871
1196
  StatefulStateStore,
872
- StatelessStateStore
1197
+ StatelessStateStore,
1198
+ isMfaRequiredError
873
1199
  });
874
1200
  //# sourceMappingURL=index.cjs.map