@auth0/auth0-server-js 1.12.1 → 1.13.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
@@ -168,6 +168,7 @@ function updateStateDataForConnectionTokenSet(options, stateData, tokenEndpointR
168
168
  import {
169
169
  TokenForConnectionError,
170
170
  AuthClient,
171
+ MissingCapturedResponseError,
171
172
  OrganizationValidationError,
172
173
  PasswordlessStartError,
173
174
  PasswordlessVerifyError,
@@ -211,7 +212,7 @@ function getTelemetryConfig(config) {
211
212
  return {
212
213
  enabled: true,
213
214
  name: config?.name ?? "@auth0/auth0-server-js",
214
- version: config?.version ?? "1.12.1"
215
+ version: config?.version ?? "1.13.0"
215
216
  };
216
217
  }
217
218
 
@@ -231,8 +232,8 @@ var ServerMfaClient = class {
231
232
  * @returns Promise resolving to an array of enrolled authenticators
232
233
  * @throws {MfaListAuthenticatorsError} When the request fails
233
234
  */
234
- async listAuthenticators(options) {
235
- return this.#options.authClient.mfa.listAuthenticators(options);
235
+ async listAuthenticators(options, requestOptions) {
236
+ return this.#options.authClient.mfa.listAuthenticators(options, requestOptions);
236
237
  }
237
238
  /**
238
239
  * Enrolls a new MFA authenticator for the user.
@@ -241,8 +242,8 @@ var ServerMfaClient = class {
241
242
  * @returns Promise resolving to enrollment response with authenticator details
242
243
  * @throws {MfaEnrollmentError} When enrollment fails
243
244
  */
244
- async enrollAuthenticator(options) {
245
- return this.#options.authClient.mfa.enrollAuthenticator(options);
245
+ async enrollAuthenticator(options, requestOptions) {
246
+ return this.#options.authClient.mfa.enrollAuthenticator(options, requestOptions);
246
247
  }
247
248
  /**
248
249
  * Initiates an MFA challenge for user verification.
@@ -251,8 +252,8 @@ var ServerMfaClient = class {
251
252
  * @returns Promise resolving to challenge response with challenge details
252
253
  * @throws {MfaChallengeError} When the challenge fails
253
254
  */
254
- async challengeAuthenticator(options) {
255
- return this.#options.authClient.mfa.challengeAuthenticator(options);
255
+ async challengeAuthenticator(options, requestOptions) {
256
+ return this.#options.authClient.mfa.challengeAuthenticator(options, requestOptions);
256
257
  }
257
258
  /**
258
259
  * Verifies an MFA challenge and completes the authentication flow.
@@ -266,8 +267,8 @@ var ServerMfaClient = class {
266
267
  * @returns The tokens returned by Auth0 after successful verification
267
268
  * @throws {MfaVerifyError} When verification fails (e.g. invalid token, wrong code)
268
269
  */
269
- async verify(options, storeOptions) {
270
- const tokenResponse = await this.#options.authClient.mfa.verify(options);
270
+ async verify(options, storeOptions, requestOptions) {
271
+ const tokenResponse = await this.#options.authClient.mfa.verify(options, requestOptions);
271
272
  const audience = options.audience ?? this.#options.defaultAudience;
272
273
  const existingStateData = await this.#options.stateStore.get(
273
274
  this.#options.stateStoreIdentifier,
@@ -330,10 +331,10 @@ var ServerPasskeyClient = class {
330
331
  *
331
332
  * @returns A promise resolving to the signup challenge.
332
333
  */
333
- async register(options, storeOptions) {
334
+ async register(options, storeOptions, requestOptions) {
334
335
  const domain = await this.#options.resolveDomain(storeOptions);
335
336
  const authClient = this.#options.getAuthClient(domain);
336
- return authClient.passkey.register(options);
337
+ return authClient.passkey.register(options, requestOptions);
337
338
  }
338
339
  /**
339
340
  * Requests a passkey login challenge for an existing user.
@@ -355,10 +356,10 @@ var ServerPasskeyClient = class {
355
356
  *
356
357
  * @returns A promise resolving to the login challenge.
357
358
  */
358
- async challenge(options, storeOptions) {
359
+ async challenge(options, storeOptions, requestOptions) {
359
360
  const domain = await this.#options.resolveDomain(storeOptions);
360
361
  const authClient = this.#options.getAuthClient(domain);
361
- return authClient.passkey.challenge(options);
362
+ return authClient.passkey.challenge(options, requestOptions);
362
363
  }
363
364
  /**
364
365
  * Completes a passkey authentication flow (signup or login) by exchanging the
@@ -380,7 +381,7 @@ var ServerPasskeyClient = class {
380
381
  *
381
382
  * @returns A promise resolving to an object containing the authorizationDetails (when RAR was used).
382
383
  */
383
- async getToken(options, storeOptions) {
384
+ async getToken(options, storeOptions, requestOptions) {
384
385
  const scope = ensureOpenIdScope(options.scope ?? this.#options.defaultScope);
385
386
  const audience = options.audience ?? this.#options.defaultAudience;
386
387
  const domain = await this.#options.resolveDomain(storeOptions);
@@ -389,7 +390,7 @@ var ServerPasskeyClient = class {
389
390
  ...options,
390
391
  scope,
391
392
  audience
392
- });
393
+ }, requestOptions);
393
394
  const existingStateData = await this.#options.stateStore.get(this.#options.stateStoreIdentifier, storeOptions);
394
395
  const stateData = updateStateData(audience ?? "default", existingStateData, tokenEndpointResponse, { domain });
395
396
  await this.#options.stateStore.set(this.#options.stateStoreIdentifier, stateData, true, storeOptions);
@@ -422,9 +423,9 @@ var ServerDatabaseClient = class {
422
423
  *
423
424
  * @returns A promise resolving to the created user result with a normalized `id` field.
424
425
  */
425
- async signUp(options, storeOptions) {
426
+ async signUp(options, storeOptions, requestOptions) {
426
427
  const domain = await this.#options.resolveDomain(storeOptions);
427
- return this.#options.getAuthClient(domain).database.signUp(options);
428
+ return this.#options.getAuthClient(domain).database.signUp(options, requestOptions);
428
429
  }
429
430
  /**
430
431
  * Requests a password-change email for a database connection user.
@@ -440,9 +441,9 @@ var ServerDatabaseClient = class {
440
441
  *
441
442
  * @returns A promise resolving to the server's plain-text confirmation message.
442
443
  */
443
- async changePassword(options, storeOptions) {
444
+ async changePassword(options, storeOptions, requestOptions) {
444
445
  const domain = await this.#options.resolveDomain(storeOptions);
445
- return this.#options.getAuthClient(domain).database.changePassword(options);
446
+ return this.#options.getAuthClient(domain).database.changePassword(options, requestOptions);
446
447
  }
447
448
  };
448
449
 
@@ -717,6 +718,7 @@ var ServerClient = class {
717
718
  * Takes an URL, extract the Authorization Code flow query parameters and requests a token.
718
719
  * @param url The URl from which the query params should be extracted to exchange for a token.
719
720
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
721
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the code-for-token exchange.
720
722
  *
721
723
  * @throws {MissingTransactionError} When no transaction was found.
722
724
  * @throws {TokenByCodeError} If there was an issue requesting the access token.
@@ -724,8 +726,15 @@ var ServerClient = class {
724
726
  * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
725
727
  *
726
728
  * @returns A promise resolving to an object, containing the original appState (if present) and the authorizationDetails (when RAR was used).
729
+ *
730
+ * @remarks
731
+ * This method does not support the `fullResponse` opt-in in v1. It accepts
732
+ * `url` and `storeOptions` with no intermediate options object; adding
733
+ * `fullResponse` would require a new options parameter and is deferred to
734
+ * a later revision.
735
+ * TODO(#<issue-number>): add fullResponse overload to completeInteractiveLogin in a future minor.
727
736
  */
728
- async completeInteractiveLogin(url, storeOptions) {
737
+ async completeInteractiveLogin(url, storeOptions, requestOptions) {
729
738
  const transactionData = await this.#transactionStore.get(this.#transactionStoreIdentifier, storeOptions);
730
739
  if (!transactionData) {
731
740
  throw new MissingTransactionError();
@@ -736,7 +745,7 @@ var ServerClient = class {
736
745
  // TransactionData.codeVerifier is optional only to accommodate magic-link transactions.
737
746
  codeVerifier: transactionData.codeVerifier,
738
747
  organization: transactionData.organization
739
- });
748
+ }, requestOptions);
740
749
  await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
741
750
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
742
751
  const stateData = applySessionExpiryAtLogin(
@@ -800,14 +809,15 @@ var ServerClient = class {
800
809
  * Takes an URL, extract the Authorization Code flow query parameters and requests a token.
801
810
  * @param url The URl from which the query params should be extracted to exchange for a token.
802
811
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
812
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the code-for-token exchange.
803
813
  *
804
814
  * @throws {MissingTransactionError} When no transaction was found.
805
815
  * @throws {TokenByCodeError} If there was an issue requesting the access token.
806
816
  *
807
817
  * @returns A promise resolving to an object, containing the original appState (if present).
808
818
  */
809
- async completeLinkUser(url, storeOptions) {
810
- const result = await this.completeInteractiveLogin(url, storeOptions);
819
+ async completeLinkUser(url, storeOptions, requestOptions) {
820
+ const result = await this.completeInteractiveLogin(url, storeOptions, requestOptions);
811
821
  return {
812
822
  appState: result.appState
813
823
  };
@@ -863,43 +873,44 @@ var ServerClient = class {
863
873
  * Takes an URL, extract the Authorization Code flow query parameters and requests a token.
864
874
  * @param url The URl from which the query params should be extracted to exchange for a token.
865
875
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
876
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the code-for-token exchange.
866
877
  *
867
878
  * @throws {MissingTransactionError} When no transaction was found.
868
879
  * @throws {TokenByCodeError} If there was an issue requesting the access token.
869
880
  *
870
881
  * @returns A promise resolving to an object, containing the original appState (if present).
871
882
  */
872
- async completeUnlinkUser(url, storeOptions) {
873
- const result = await this.completeInteractiveLogin(url, storeOptions);
883
+ async completeUnlinkUser(url, storeOptions, requestOptions) {
884
+ const result = await this.completeInteractiveLogin(url, storeOptions, requestOptions);
874
885
  return {
875
886
  appState: result.appState
876
887
  };
877
888
  }
878
- /**
879
- * Logs in using Client-Initiated Backchannel Authentication.
880
- *
881
- * Using Client-Initiated Backchannel Authentication requires the feature to be enabled in the Auth0 dashboard.
882
- * @see https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow
883
- * @param options Options used to configure the backchannel login process.
884
- * @param storeOptions Optional options used to pass to the Transaction and State Store.
885
- *
886
- * @throws {BackchannelAuthenticationError} If there was an issue when doing backchannel authentication.
887
- * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
888
- *
889
- * @returns A promise resolving to an object, containing the authorizationDetails (when RAR was used).
890
- */
891
- async loginBackchannel(options, storeOptions) {
889
+ async loginBackchannel(options, storeOptions, requestOptions) {
892
890
  const scope = ensureOpenIdScope(options.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
893
891
  const domain = await this.#resolveDomain(storeOptions);
894
892
  const authClient = this.#getAuthClient(domain);
895
- const tokenEndpointResponse = await authClient.backchannelAuthentication({
896
- bindingMessage: options.bindingMessage,
897
- loginHint: options.loginHint,
898
- authorizationParams: {
899
- ...options.authorizationParams,
900
- scope
901
- }
902
- });
893
+ let response;
894
+ let tokenEndpointResponse;
895
+ if (options.fullResponse) {
896
+ const authJsResult = await authClient.backchannelAuthentication({
897
+ bindingMessage: options.bindingMessage,
898
+ loginHint: options.loginHint,
899
+ authorizationParams: { ...options.authorizationParams, scope },
900
+ fullResponse: true
901
+ }, requestOptions);
902
+ tokenEndpointResponse = authJsResult.data;
903
+ response = authJsResult.response;
904
+ } else {
905
+ tokenEndpointResponse = await authClient.backchannelAuthentication({
906
+ bindingMessage: options.bindingMessage,
907
+ loginHint: options.loginHint,
908
+ authorizationParams: {
909
+ ...options.authorizationParams,
910
+ scope
911
+ }
912
+ }, requestOptions);
913
+ }
903
914
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
904
915
  const stateData = applySessionExpiryAtLogin(
905
916
  updateStateData(this.#options.authorizationParams?.audience ?? "default", existingStateData, tokenEndpointResponse, {
@@ -908,9 +919,16 @@ var ServerClient = class {
908
919
  tokenEndpointResponse.claims
909
920
  );
910
921
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
911
- return {
922
+ const result = {
912
923
  authorizationDetails: tokenEndpointResponse.authorizationDetails
913
924
  };
925
+ if (options.fullResponse) {
926
+ if (!response) {
927
+ throw new MissingCapturedResponseError();
928
+ }
929
+ return { data: result, response };
930
+ }
931
+ return result;
914
932
  }
915
933
  /**
916
934
  * Starts a passwordless flow by sending a one-time code (OTP) or a magic link.
@@ -933,6 +951,7 @@ var ServerClient = class {
933
951
  *
934
952
  * @param options Discriminated start options.
935
953
  * @param storeOptions Optional options passed to the resolver / stores.
954
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the `/passwordless/start` request.
936
955
  *
937
956
  * @throws {PasswordlessStartError} If the request fails, or if a magic link is requested without a `redirectUri`.
938
957
  *
@@ -949,22 +968,28 @@ var ServerClient = class {
949
968
  * redirectUri: 'https://app.example.com/auth/callback',
950
969
  * });
951
970
  */
952
- async startPasswordless(options, storeOptions) {
971
+ async startPasswordless(options, storeOptions, requestOptions) {
953
972
  const domain = await this.#resolveDomain(storeOptions);
954
973
  const authClient = this.#getAuthClient(domain);
955
974
  if (options.connection === "sms") {
956
- await authClient.passwordless.sendSms({
957
- phoneNumber: options.phoneNumber,
958
- language: options.language
959
- });
975
+ await authClient.passwordless.sendSms(
976
+ {
977
+ phoneNumber: options.phoneNumber,
978
+ language: options.language
979
+ },
980
+ requestOptions
981
+ );
960
982
  return;
961
983
  }
962
984
  if (options.send !== "link") {
963
- await authClient.passwordless.sendEmail({
964
- email: options.email,
965
- send: "code",
966
- language: options.language
967
- });
985
+ await authClient.passwordless.sendEmail(
986
+ {
987
+ email: options.email,
988
+ send: "code",
989
+ language: options.language
990
+ },
991
+ requestOptions
992
+ );
968
993
  return;
969
994
  }
970
995
  if (!options.redirectUri || typeof options.redirectUri !== "string") {
@@ -973,19 +998,22 @@ var ServerClient = class {
973
998
  const state = crypto.randomUUID();
974
999
  const scope = ensureOpenIdScope(options.scope ?? this.#options.authorizationParams?.scope);
975
1000
  const audience = options.audience ?? this.#options.authorizationParams?.audience;
976
- await authClient.passwordless.sendEmail({
977
- email: options.email,
978
- send: "link",
979
- language: options.language,
980
- authParams: {
981
- ...options.authParams,
982
- redirect_uri: options.redirectUri,
983
- response_type: "code",
984
- scope,
985
- ...audience ? { audience } : {},
986
- state
987
- }
988
- });
1001
+ await authClient.passwordless.sendEmail(
1002
+ {
1003
+ email: options.email,
1004
+ send: "link",
1005
+ language: options.language,
1006
+ authParams: {
1007
+ ...options.authParams,
1008
+ redirect_uri: options.redirectUri,
1009
+ response_type: "code",
1010
+ scope,
1011
+ ...audience ? { audience } : {},
1012
+ state
1013
+ }
1014
+ },
1015
+ requestOptions
1016
+ );
989
1017
  const transactionState = {
990
1018
  audience,
991
1019
  domain,
@@ -993,42 +1021,42 @@ var ServerClient = class {
993
1021
  };
994
1022
  await this.#transactionStore.set(this.#transactionStoreIdentifier, transactionState, false, storeOptions);
995
1023
  }
996
- /**
997
- * Completes a passwordless OTP login and persists the resulting session.
998
- *
999
- * Discriminated on `connection` to mirror the `@auth0/nextjs-auth0` `passwordless.verify()`
1000
- * surface. Non-redirect flow: no PKCE and no transaction store (mirrors
1001
- * {@link ServerClient#loginBackchannel}). The `openid` scope is always ensured by this layer.
1002
- *
1003
- * Note: the state store is read-then-written; if your deployment performs concurrent
1004
- * logins for the same session identifier, use a state store with atomic/serializable
1005
- * writes to avoid last-write-wins races.
1006
- *
1007
- * @param options Discriminated completion options (`connection`, identifier, `verificationCode`).
1008
- * @param storeOptions Optional options passed to the resolver / stores.
1009
- *
1010
- * @throws {PasswordlessVerifyError} If the code is invalid, expired, or rate-limited. When the
1011
- * connection requires MFA, the server responds with `mfa_required`; narrow the thrown error
1012
- * with `isMfaRequiredError(error)` to read `cause.mfa_token`.
1013
- *
1014
- * @returns A promise resolving to the authorizationDetails (when RAR was used).
1015
- */
1016
- async completePasswordless(options, storeOptions) {
1024
+ async completePasswordless(options, storeOptions, requestOptions) {
1017
1025
  const scope = ensureOpenIdScope(options.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
1018
1026
  const audience = options.authorizationParams?.audience ?? this.#options.authorizationParams?.audience;
1019
1027
  const domain = await this.#resolveDomain(storeOptions);
1020
1028
  const authClient = this.#getAuthClient(domain);
1021
- const tokenEndpointResponse = options.connection === "sms" ? await authClient.getTokenByPasswordlessSms({
1022
- phoneNumber: options.phoneNumber,
1023
- code: options.verificationCode,
1024
- audience,
1025
- scope
1026
- }) : await authClient.getTokenByPasswordlessEmail({
1027
- email: options.email,
1028
- code: options.verificationCode,
1029
- audience,
1030
- scope
1031
- });
1029
+ let response;
1030
+ let tokenEndpointResponse;
1031
+ if (options.fullResponse) {
1032
+ const authJsResult = options.connection === "sms" ? await authClient.getTokenByPasswordlessSms({
1033
+ phoneNumber: options.phoneNumber,
1034
+ code: options.verificationCode,
1035
+ audience,
1036
+ scope,
1037
+ fullResponse: true
1038
+ }, requestOptions) : await authClient.getTokenByPasswordlessEmail({
1039
+ email: options.email,
1040
+ code: options.verificationCode,
1041
+ audience,
1042
+ scope,
1043
+ fullResponse: true
1044
+ }, requestOptions);
1045
+ tokenEndpointResponse = authJsResult.data;
1046
+ response = authJsResult.response;
1047
+ } else {
1048
+ tokenEndpointResponse = options.connection === "sms" ? await authClient.getTokenByPasswordlessSms({
1049
+ phoneNumber: options.phoneNumber,
1050
+ code: options.verificationCode,
1051
+ audience,
1052
+ scope
1053
+ }, requestOptions) : await authClient.getTokenByPasswordlessEmail({
1054
+ email: options.email,
1055
+ code: options.verificationCode,
1056
+ audience,
1057
+ scope
1058
+ }, requestOptions);
1059
+ }
1032
1060
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
1033
1061
  const stateData = updateStateData(
1034
1062
  this.#options.authorizationParams?.audience ?? "default",
@@ -1037,9 +1065,16 @@ var ServerClient = class {
1037
1065
  { domain }
1038
1066
  );
1039
1067
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
1040
- return {
1068
+ const result = {
1041
1069
  authorizationDetails: tokenEndpointResponse.authorizationDetails
1042
1070
  };
1071
+ if (options.fullResponse) {
1072
+ if (!response) {
1073
+ throw new MissingCapturedResponseError();
1074
+ }
1075
+ return { data: result, response };
1076
+ }
1077
+ return result;
1043
1078
  }
1044
1079
  /**
1045
1080
  * Completes a passwordless magic-link login and persists the resulting session.
@@ -1051,6 +1086,7 @@ var ServerClient = class {
1051
1086
  *
1052
1087
  * @param url The callback URL containing the authorization `code` and `state`.
1053
1088
  * @param storeOptions Optional options passed to the resolver / stores.
1089
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the code exchange.
1054
1090
  *
1055
1091
  * @throws {MissingTransactionError} If no magic-link transaction was found.
1056
1092
  * @throws {PasswordlessVerifyError} If the returned `state` is missing or does not match.
@@ -1061,7 +1097,7 @@ var ServerClient = class {
1061
1097
  * @example
1062
1098
  * const result = await serverClient.completePasswordlessMagicLink(callbackUrl, storeOptions);
1063
1099
  */
1064
- async completePasswordlessMagicLink(url, storeOptions) {
1100
+ async completePasswordlessMagicLink(url, storeOptions, requestOptions) {
1065
1101
  const transactionData = await this.#transactionStore.get(this.#transactionStoreIdentifier, storeOptions);
1066
1102
  if (!transactionData) {
1067
1103
  throw new MissingTransactionError();
@@ -1073,7 +1109,7 @@ var ServerClient = class {
1073
1109
  }
1074
1110
  const domain = transactionData.domain ?? await this.#resolveDomain(storeOptions);
1075
1111
  const authClient = this.#getAuthClient(domain);
1076
- const tokenEndpointResponse = await authClient.getTokenByMagicLinkCode(url, { expectedState });
1112
+ const tokenEndpointResponse = await authClient.getTokenByMagicLinkCode(url, { expectedState }, requestOptions);
1077
1113
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
1078
1114
  const stateData = updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse, {
1079
1115
  domain
@@ -1086,6 +1122,12 @@ var ServerClient = class {
1086
1122
  }
1087
1123
  /**
1088
1124
  * Retrieves the user from the store, or undefined if no user found.
1125
+ *
1126
+ * This does not accept `RequestOptions`. It is a pure read from the state store and makes no
1127
+ * network call, so a per-request `signal`/`headers`/`customFetch` could not take effect. The
1128
+ * exclusion is deliberate: a parameter that can never do anything costs the public surface more
1129
+ * than the asymmetry with `getAccessToken`/`getAccessTokenForConnection`/`revokeRefreshToken` does.
1130
+ *
1089
1131
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
1090
1132
  * @returns The user, or undefined if no user found in the store.
1091
1133
  */
@@ -1128,6 +1170,34 @@ var ServerClient = class {
1128
1170
  return sessionData;
1129
1171
  }
1130
1172
  }
1173
+ /**
1174
+ * Retrieves the OIDC UserInfo claims for a given access token.
1175
+ *
1176
+ * The access token must be supplied explicitly by the caller. This method does NOT read
1177
+ * the token from the session and does NOT trigger a refresh. The token must be accepted by
1178
+ * the `/userinfo` endpoint:
1179
+ * - Without Multi-Resource Refresh Tokens (MRRT): pass a default OIDC access token, one
1180
+ * obtained without an explicit `audience` parameter.
1181
+ * - With MRRT: tokens are audience-bound, so request the userinfo endpoint as the audience
1182
+ * (e.g. `https://<domain>/userinfo`) when obtaining the token. A token bound to a
1183
+ * different resource-server audience is rejected by `/userinfo`.
1184
+ *
1185
+ * `/userinfo` is a bearer-protected resource and requires no client authentication, so this
1186
+ * works for public clients: the supplied access token is the only credential used.
1187
+ *
1188
+ * @param options Options containing the access token and an optional expected subject
1189
+ * for OIDC subject-consistency validation.
1190
+ * @param storeOptions Optional store options, used to resolve the domain in resolver mode.
1191
+ * @param requestOptions Optional per-request options (signal, headers, customFetch) forwarded
1192
+ * to the underlying `/userinfo` request.
1193
+ * @throws {UserInfoError} When the `/userinfo` request fails or the subject check fails.
1194
+ * @returns A Promise resolving to the UserInfo claims.
1195
+ */
1196
+ async getUserInfo(options, storeOptions, requestOptions) {
1197
+ const domain = await this.#resolveDomain(storeOptions);
1198
+ const authClient = this.#getAuthClient(domain);
1199
+ return authClient.getUserInfo(options, requestOptions);
1200
+ }
1131
1201
  /**
1132
1202
  * 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.
1133
1203
  * Also updates the store when a new token was retrieved from Auth0.
@@ -1136,19 +1206,30 @@ var ServerClient = class {
1136
1206
  * request an access token for that audience/scope (Multi-Resource Refresh Tokens). Tokens are cached per
1137
1207
  * audience and scope combination.
1138
1208
  *
1139
- * @param options Optional options for requesting a specific audience/scope.
1209
+ * When `options.fullResponse` is `true`, the method returns an {@link ApiResponse} envelope containing both
1210
+ * the token set and the raw {@link Response} from the token endpoint. The cache is bypassed in this case,
1211
+ * forcing a refresh-token call even when a valid cached token exists, because the `Response` can only be
1212
+ * produced by a live HTTP call.
1213
+ *
1214
+ * @param options Optional options for requesting a specific audience/scope or enabling full response.
1140
1215
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
1216
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Only supported with the options form (second overload). A cache hit returns before any network call, so `requestOptions` (including `signal`) is a no-op on that path; it applies only to the refresh-token exchange on a cache miss.
1217
+ *
1218
+ * @remarks
1219
+ * Legacy single-argument form: `getAccessToken(storeOptions?)`. If your `TStoreOptions` type
1220
+ * contains `audience` or `scope` keys, use the explicit two-argument form instead:
1221
+ * `getAccessToken({}, storeOptions)` to avoid call-site routing ambiguity.
1141
1222
  *
1142
1223
  * @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`.
1143
1224
  * @throws {SessionExpiredError} When the session's `session_expiry` ceiling has been reached; the session is cleared and no refresh is attempted — the user must re-authenticate.
1144
1225
  *
1145
- * @returns The Token Set, containing the access token, as well as additional information.
1226
+ * @returns The Token Set when `fullResponse` is omitted, or an {@link ApiResponse} envelope when `fullResponse: true`.
1146
1227
  */
1147
- async getAccessToken(tokenOptionsOrStoreOptions, storeOptions) {
1228
+ async getAccessToken(tokenOptionsOrStoreOptions, storeOptions, requestOptions) {
1148
1229
  const hasTokenOptions = (
1149
1230
  // If second arg exists, first arg must be GetAccessTokenOptions
1150
- storeOptions !== void 0 || // OR if first arg has audience/scope properties
1151
- !!tokenOptionsOrStoreOptions && typeof tokenOptionsOrStoreOptions === "object" && ("audience" in tokenOptionsOrStoreOptions || "scope" in tokenOptionsOrStoreOptions)
1231
+ storeOptions !== void 0 || // OR if first arg has audience, scope, or fullResponse properties
1232
+ !!tokenOptionsOrStoreOptions && typeof tokenOptionsOrStoreOptions === "object" && ("audience" in tokenOptionsOrStoreOptions || "scope" in tokenOptionsOrStoreOptions || "fullResponse" in tokenOptionsOrStoreOptions)
1152
1233
  );
1153
1234
  const [resolvedOptions, resolvedStoreOptions] = hasTokenOptions ? [tokenOptionsOrStoreOptions, storeOptions] : [void 0, tokenOptionsOrStoreOptions];
1154
1235
  const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, resolvedStoreOptions);
@@ -1176,7 +1257,9 @@ var ServerClient = class {
1176
1257
  (tokenSet2) => tokenSet2.audience === audience && (!scope || compareScopes(tokenSet2.scope, scope))
1177
1258
  );
1178
1259
  if (tokenSet && tokenSet.expiresAt > Date.now() / 1e3) {
1179
- return tokenSet;
1260
+ if (!resolvedOptions?.fullResponse) {
1261
+ return tokenSet;
1262
+ }
1180
1263
  }
1181
1264
  if (!stateData?.refreshToken) {
1182
1265
  throw new TokenByRefreshTokenError(
@@ -1193,35 +1276,38 @@ var ServerClient = class {
1193
1276
  ...scope && { scope }
1194
1277
  }
1195
1278
  };
1196
- const tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenByRefreshToken(tokenByRefreshTokenOptions);
1279
+ let response;
1280
+ let tokenEndpointResponse;
1281
+ if (resolvedOptions?.fullResponse) {
1282
+ const authJsResult = await this.#getAuthClient(domainForSession).getTokenByRefreshToken({
1283
+ ...tokenByRefreshTokenOptions,
1284
+ fullResponse: true
1285
+ }, requestOptions);
1286
+ tokenEndpointResponse = authJsResult.data;
1287
+ response = authJsResult.response;
1288
+ } else {
1289
+ tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenByRefreshToken(tokenByRefreshTokenOptions, requestOptions);
1290
+ }
1197
1291
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, resolvedStoreOptions);
1198
1292
  const updatedStateData = updateStateData(audience, existingStateData, tokenEndpointResponse, {
1199
1293
  domain: domainForSession
1200
1294
  });
1201
1295
  await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, resolvedStoreOptions);
1202
- return {
1296
+ const returnTokenSet = {
1203
1297
  accessToken: tokenEndpointResponse.accessToken,
1204
1298
  scope: tokenEndpointResponse.scope,
1205
1299
  expiresAt: tokenEndpointResponse.expiresAt,
1206
1300
  audience
1207
1301
  };
1302
+ if (resolvedOptions?.fullResponse) {
1303
+ if (!response) {
1304
+ throw new MissingCapturedResponseError();
1305
+ }
1306
+ return { data: returnTokenSet, response };
1307
+ }
1308
+ return returnTokenSet;
1208
1309
  }
1209
- /**
1210
- * Retrieves an access token for a connection.
1211
- *
1212
- * This method attempts to obtain an access token for a specified connection.
1213
- * It first checks if a refresh token exists in the store.
1214
- * If no refresh token is found, it throws an `AccessTokenForConnectionError` indicating
1215
- * that the refresh token was not found.
1216
- *
1217
- * @param options - Options for retrieving an access token for a connection.
1218
- * @param storeOptions Optional options used to pass to the Transaction and State Store.
1219
- *
1220
- * @throws {TokenForConnectionError} If the refresh token was not found or there was an issue requesting the access token.
1221
- *
1222
- * @returns The Connection Token Set, containing the access token for the connection, as well as additional information.
1223
- */
1224
- async getAccessTokenForConnection(options, storeOptions) {
1310
+ async getAccessTokenForConnection(options, storeOptions, requestOptions) {
1225
1311
  const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
1226
1312
  const sessionDomain = stateData ? this.#getSessionDomain(stateData) : this.#staticDomain;
1227
1313
  if (this.#isResolverMode()) {
@@ -1240,7 +1326,9 @@ var ServerClient = class {
1240
1326
  (tokenSet) => tokenSet.connection === options.connection
1241
1327
  );
1242
1328
  if (connectionTokenSet && connectionTokenSet.expiresAt > Date.now() / 1e3) {
1243
- return connectionTokenSet;
1329
+ if (!options.fullResponse) {
1330
+ return connectionTokenSet;
1331
+ }
1244
1332
  }
1245
1333
  if (!stateData?.refreshToken) {
1246
1334
  throw new TokenForConnectionError(
@@ -1248,11 +1336,24 @@ var ServerClient = class {
1248
1336
  );
1249
1337
  }
1250
1338
  const domainForSession = sessionDomain;
1251
- const tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenForConnection({
1252
- connection: options.connection,
1253
- loginHint: options.loginHint,
1254
- refreshToken: stateData.refreshToken
1255
- });
1339
+ let response;
1340
+ let tokenEndpointResponse;
1341
+ if (options.fullResponse) {
1342
+ const authJsResult = await this.#getAuthClient(domainForSession).getTokenForConnection({
1343
+ connection: options.connection,
1344
+ loginHint: options.loginHint,
1345
+ refreshToken: stateData.refreshToken,
1346
+ fullResponse: true
1347
+ }, requestOptions);
1348
+ tokenEndpointResponse = authJsResult.data;
1349
+ response = authJsResult.response;
1350
+ } else {
1351
+ tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenForConnection({
1352
+ connection: options.connection,
1353
+ loginHint: options.loginHint,
1354
+ refreshToken: stateData.refreshToken
1355
+ }, requestOptions);
1356
+ }
1256
1357
  const updatedStateData = updateStateDataForConnectionTokenSet(
1257
1358
  options,
1258
1359
  {
@@ -1262,13 +1363,20 @@ var ServerClient = class {
1262
1363
  tokenEndpointResponse
1263
1364
  );
1264
1365
  await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, storeOptions);
1265
- return {
1366
+ const returnConnectionTokenSet = {
1266
1367
  accessToken: tokenEndpointResponse.accessToken,
1267
1368
  scope: tokenEndpointResponse.scope,
1268
1369
  expiresAt: tokenEndpointResponse.expiresAt,
1269
1370
  connection: options.connection,
1270
1371
  loginHint: options.loginHint
1271
1372
  };
1373
+ if (options.fullResponse) {
1374
+ if (!response) {
1375
+ throw new MissingCapturedResponseError();
1376
+ }
1377
+ return { data: returnConnectionTokenSet, response };
1378
+ }
1379
+ return returnConnectionTokenSet;
1272
1380
  }
1273
1381
  /**
1274
1382
  * Revokes the refresh token stored in the current session, or an explicitly supplied token.
@@ -1280,12 +1388,13 @@ var ServerClient = class {
1280
1388
  *
1281
1389
  * @param options Optionally supply a token to revoke instead of reading from the session.
1282
1390
  * @param storeOptions Optional options passed to the StateStore.
1391
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the revocation request.
1283
1392
  *
1284
1393
  * @throws {MissingRequiredArgumentError} If `options.token` is an empty string.
1285
1394
  * @throws {MissingSessionError} If no refresh token is found in the session and none was provided.
1286
1395
  * @throws {TokenRevocationError} If the revocation request fails.
1287
1396
  */
1288
- async revokeRefreshToken(options = {}, storeOptions) {
1397
+ async revokeRefreshToken(options = {}, storeOptions, requestOptions) {
1289
1398
  if (options.token !== void 0 && options.token.length === 0) {
1290
1399
  throw new MissingRequiredArgumentError("options.token must not be an empty string.");
1291
1400
  }
@@ -1309,18 +1418,19 @@ var ServerClient = class {
1309
1418
  } else {
1310
1419
  authClient = this.authClient;
1311
1420
  }
1312
- await authClient.revokeToken({ token: refreshToken, tokenTypeHint: "refresh_token" });
1421
+ await authClient.revokeToken({ token: refreshToken, tokenTypeHint: "refresh_token" }, requestOptions);
1313
1422
  }
1314
1423
  /**
1315
1424
  * Logs the user out and returns a URL to redirect the user-agent to after they log out.
1316
1425
  * @param options Options used to configure the logout process.
1317
1426
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
1427
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the token revocation ONLY. Building the logout URL is local string work and issues no request, so nothing here can affect it.
1318
1428
  * @returns {URL}
1319
1429
  */
1320
- async logout(options, storeOptions) {
1430
+ async logout(options, storeOptions, requestOptions) {
1321
1431
  if (!this.#isResolverMode()) {
1322
1432
  try {
1323
- await this.revokeRefreshToken({}, storeOptions);
1433
+ await this.revokeRefreshToken({}, storeOptions, requestOptions);
1324
1434
  } catch {
1325
1435
  }
1326
1436
  await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
@@ -1336,39 +1446,33 @@ var ServerClient = class {
1336
1446
  const domainMatches = sessionDomain === resolvedDomain;
1337
1447
  if (domainMatches) {
1338
1448
  try {
1339
- await this.revokeRefreshToken({}, storeOptions);
1449
+ await this.revokeRefreshToken({}, storeOptions, requestOptions);
1340
1450
  } catch {
1341
1451
  }
1342
1452
  await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
1343
1453
  }
1344
1454
  return authClient.buildLogoutUrl(options);
1345
1455
  }
1346
- /**
1347
- * Exchanges a custom token for Auth0 tokens and persists the resulting session (RFC 8693).
1348
- *
1349
- * Calls the token endpoint using the RFC 8693 Token Exchange grant, then stores the
1350
- * resulting tokens in the StateStore — effectively logging the user in without an
1351
- * interactive browser flow. Use this when the caller already holds a trusted external
1352
- * token (e.g. a Google ID token, a legacy system token) and wants to establish an
1353
- * Auth0 session from it.
1354
- *
1355
- * Requires a Token Exchange Profile configured in your Auth0 tenant.
1356
- *
1357
- * @param options Options for the custom token exchange, including the subject token and its type.
1358
- * @param storeOptions Optional options passed to the StateStore.
1359
- *
1360
- * @throws {TokenExchangeError} If the exchange fails or the subject token is invalid.
1361
- * @throws {MissingClientAuthError} If client credentials are not configured.
1362
- *
1363
- * @returns A promise resolving to an object containing `authorizationDetails` when RAR was used.
1364
- */
1365
- async loginWithCustomTokenExchange(options, storeOptions) {
1456
+ async loginWithCustomTokenExchange(options, storeOptions, requestOptions) {
1366
1457
  const domain = await this.#resolveDomain(storeOptions);
1367
1458
  const authClient = this.#getAuthClient(domain);
1368
- const tokenEndpointResponse = await authClient.exchangeToken({
1369
- ...options,
1370
- scope: ensureOpenIdScope(options.scope)
1371
- });
1459
+ let response;
1460
+ let tokenEndpointResponse;
1461
+ if (options.fullResponse) {
1462
+ const { fullResponse: _, ...rest } = options;
1463
+ const authJsResult = await authClient.exchangeToken({
1464
+ ...rest,
1465
+ scope: ensureOpenIdScope(options.scope),
1466
+ fullResponse: true
1467
+ }, requestOptions);
1468
+ tokenEndpointResponse = authJsResult.data;
1469
+ response = authJsResult.response;
1470
+ } else {
1471
+ tokenEndpointResponse = await authClient.exchangeToken({
1472
+ ...options,
1473
+ scope: ensureOpenIdScope(options.scope)
1474
+ }, requestOptions);
1475
+ }
1372
1476
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
1373
1477
  const stateData = updateStateData(
1374
1478
  this.#options.authorizationParams?.audience ?? "default",
@@ -1377,30 +1481,25 @@ var ServerClient = class {
1377
1481
  { domain }
1378
1482
  );
1379
1483
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
1380
- return { authorizationDetails: tokenEndpointResponse.authorizationDetails };
1484
+ const result = {
1485
+ authorizationDetails: tokenEndpointResponse.authorizationDetails
1486
+ };
1487
+ if (options.fullResponse) {
1488
+ if (!response) {
1489
+ throw new MissingCapturedResponseError();
1490
+ }
1491
+ return { data: result, response };
1492
+ }
1493
+ return result;
1381
1494
  }
1382
- /**
1383
- * Exchanges a custom token for Auth0 tokens without establishing a session (RFC 8693).
1384
- *
1385
- * Performs the same RFC 8693 Token Exchange as `loginWithCustomTokenExchange` but
1386
- * returns the raw token response without writing anything to the StateStore. Use this
1387
- * for delegation or impersonation flows where you need downstream tokens but do not
1388
- * want to create or modify the current user session.
1389
- *
1390
- * Requires a Token Exchange Profile configured in your Auth0 tenant.
1391
- *
1392
- * @param options Options for the custom token exchange, including the subject token and its type.
1393
- * @param storeOptions Optional options passed to the StateStore (used only for domain resolution in resolver mode).
1394
- *
1395
- * @throws {TokenExchangeError} If the exchange fails or the subject token is invalid.
1396
- * @throws {MissingClientAuthError} If client credentials are not configured.
1397
- *
1398
- * @returns A promise resolving to the token response from Auth0.
1399
- */
1400
- async customTokenExchange(options, storeOptions) {
1495
+ async customTokenExchange(options, storeOptions, requestOptions) {
1401
1496
  const domain = await this.#resolveDomain(storeOptions);
1402
1497
  const authClient = this.#getAuthClient(domain);
1403
- return authClient.exchangeToken(options);
1498
+ if (options.fullResponse) {
1499
+ const { fullResponse: _, ...rest } = options;
1500
+ return authClient.exchangeToken({ ...rest, fullResponse: true }, requestOptions);
1501
+ }
1502
+ return authClient.exchangeToken(options, requestOptions);
1404
1503
  }
1405
1504
  /**
1406
1505
  * Requests a Session Transfer Token (STT) for impersonation via session transfer (RFC 8693).
@@ -1424,8 +1523,17 @@ var ServerClient = class {
1424
1523
  * {@link ServerClient.buildSessionTransferRedirect}, which is forwarded to the target's
1425
1524
  * `/authorize` on the redirect.
1426
1525
  *
1526
+ * @remarks
1527
+ * If the actor's ID token has expired, an internal refresh is performed before the
1528
+ * session transfer token exchange. This refresh call is NOT guarded by the caller's
1529
+ * requestOptions.signal — if the signal fires during this step, the abort is ignored.
1530
+ * Only the final exchangeToken call respects the signal.
1531
+ * Thread requestOptions into #resolveSessionTransferActor in a future minor if
1532
+ * callers need full-request abort coverage.
1533
+ *
1427
1534
  * @param options Options including the developer-supplied `subjectToken`/`subjectTokenType` and an optional explicit `actor`.
1428
1535
  * @param storeOptions Optional options used to read the agent session (for the actor) and resolve the request domain.
1536
+ * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the STT exchange only. Resolving the actor may refresh an expired agent session ID token, and that refresh is an internal call outside the caller's per-request scope, so it does not receive these options.
1429
1537
  *
1430
1538
  * @throws {TokenExchangeError} With code `actor_unavailable` when no explicit actor is given and no usable session ID token can be resolved — no logged-in agent, a session that belongs to a different domain in resolver mode, or an expired ID token that cannot be refreshed (raised client-side, before any network call). With the default code when the exchange itself fails; a server-side `setactor_required` or `session_transfer_disabled` condition is surfaced via `cause.error` / `cause.error_description`. An organization the tenant rejects also surfaces here.
1431
1539
  * @throws {MissingClientAuthError} When client credentials are not configured (STT requires a confidential client).
@@ -1434,7 +1542,7 @@ var ServerClient = class {
1434
1542
  *
1435
1543
  * @returns A promise resolving to a {@link SessionTransferTokenResult} containing the STT and its metadata.
1436
1544
  */
1437
- async requestSessionTransferToken(options, storeOptions) {
1545
+ async requestSessionTransferToken(options, storeOptions, requestOptions) {
1438
1546
  if (!options.subjectToken || !options.subjectToken.trim()) {
1439
1547
  throw new MissingRequiredArgumentError("subjectToken");
1440
1548
  }
@@ -1460,7 +1568,7 @@ var ServerClient = class {
1460
1568
  // `/authorize`; neither implies the other.
1461
1569
  organization: options.organization,
1462
1570
  extra: options.extra
1463
- });
1571
+ }, requestOptions);
1464
1572
  return {
1465
1573
  sessionTransferToken: response.accessToken,
1466
1574
  // Surface exactly what the server returned — never fabricate the URN, so a non-STT
@@ -1584,6 +1692,11 @@ var ServerClient = class {
1584
1692
  }
1585
1693
  /**
1586
1694
  * Handles the backchannel logout process by verifying the logout token and deleting the session from the store if the logout token was considered valid.
1695
+ *
1696
+ * This does not accept `RequestOptions`. Verification does fetch JWKS, but the auth-js method it
1697
+ * delegates to, `verifyLogoutToken`, takes no `requestOptions`, so there is nothing to forward.
1698
+ * That fetch always uses the client's configured `customFetch`.
1699
+ *
1587
1700
  * @param logoutToken The logout token to verify and use to delete the session from the store.
1588
1701
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
1589
1702
  *
@@ -1743,7 +1856,8 @@ import {
1743
1856
  OrganizationValidationError as OrganizationValidationError3,
1744
1857
  PasswordlessStartError as PasswordlessStartError2,
1745
1858
  PasswordlessVerifyError as PasswordlessVerifyError2,
1746
- isMfaRequiredError as isMfaRequiredError2
1859
+ isMfaRequiredError as isMfaRequiredError2,
1860
+ UserInfoError
1747
1861
  } from "@auth0/auth0-auth-js";
1748
1862
 
1749
1863
  // src/store/cookie-transaction-store.ts
@@ -1993,6 +2107,7 @@ export {
1993
2107
  TokenExchangeError2 as TokenExchangeError,
1994
2108
  TokenExchangeErrorCode,
1995
2109
  TokenRevocationError,
2110
+ UserInfoError,
1996
2111
  isMfaRequiredError2 as isMfaRequiredError
1997
2112
  };
1998
2113
  //# sourceMappingURL=index.js.map