@auth0/auth0-server-js 1.12.0 → 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/README.md +1 -1
- package/dist/index.cjs +312 -189
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +115 -25
- package/dist/index.d.ts +115 -25
- package/dist/index.js +314 -190
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -53,6 +53,7 @@ __export(index_exports, {
|
|
|
53
53
|
TokenExchangeError: () => import_auth0_auth_js5.TokenExchangeError,
|
|
54
54
|
TokenExchangeErrorCode: () => TokenExchangeErrorCode,
|
|
55
55
|
TokenRevocationError: () => import_auth0_auth_js5.TokenRevocationError,
|
|
56
|
+
UserInfoError: () => import_auth0_auth_js5.UserInfoError,
|
|
56
57
|
isMfaRequiredError: () => import_auth0_auth_js5.isMfaRequiredError
|
|
57
58
|
});
|
|
58
59
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -262,7 +263,7 @@ function getTelemetryConfig(config) {
|
|
|
262
263
|
return {
|
|
263
264
|
enabled: true,
|
|
264
265
|
name: config?.name ?? "@auth0/auth0-server-js",
|
|
265
|
-
version: config?.version ?? "1.
|
|
266
|
+
version: config?.version ?? "1.13.0"
|
|
266
267
|
};
|
|
267
268
|
}
|
|
268
269
|
|
|
@@ -282,8 +283,8 @@ var ServerMfaClient = class {
|
|
|
282
283
|
* @returns Promise resolving to an array of enrolled authenticators
|
|
283
284
|
* @throws {MfaListAuthenticatorsError} When the request fails
|
|
284
285
|
*/
|
|
285
|
-
async listAuthenticators(options) {
|
|
286
|
-
return this.#options.authClient.mfa.listAuthenticators(options);
|
|
286
|
+
async listAuthenticators(options, requestOptions) {
|
|
287
|
+
return this.#options.authClient.mfa.listAuthenticators(options, requestOptions);
|
|
287
288
|
}
|
|
288
289
|
/**
|
|
289
290
|
* Enrolls a new MFA authenticator for the user.
|
|
@@ -292,8 +293,8 @@ var ServerMfaClient = class {
|
|
|
292
293
|
* @returns Promise resolving to enrollment response with authenticator details
|
|
293
294
|
* @throws {MfaEnrollmentError} When enrollment fails
|
|
294
295
|
*/
|
|
295
|
-
async enrollAuthenticator(options) {
|
|
296
|
-
return this.#options.authClient.mfa.enrollAuthenticator(options);
|
|
296
|
+
async enrollAuthenticator(options, requestOptions) {
|
|
297
|
+
return this.#options.authClient.mfa.enrollAuthenticator(options, requestOptions);
|
|
297
298
|
}
|
|
298
299
|
/**
|
|
299
300
|
* Initiates an MFA challenge for user verification.
|
|
@@ -302,8 +303,8 @@ var ServerMfaClient = class {
|
|
|
302
303
|
* @returns Promise resolving to challenge response with challenge details
|
|
303
304
|
* @throws {MfaChallengeError} When the challenge fails
|
|
304
305
|
*/
|
|
305
|
-
async challengeAuthenticator(options) {
|
|
306
|
-
return this.#options.authClient.mfa.challengeAuthenticator(options);
|
|
306
|
+
async challengeAuthenticator(options, requestOptions) {
|
|
307
|
+
return this.#options.authClient.mfa.challengeAuthenticator(options, requestOptions);
|
|
307
308
|
}
|
|
308
309
|
/**
|
|
309
310
|
* Verifies an MFA challenge and completes the authentication flow.
|
|
@@ -317,8 +318,8 @@ var ServerMfaClient = class {
|
|
|
317
318
|
* @returns The tokens returned by Auth0 after successful verification
|
|
318
319
|
* @throws {MfaVerifyError} When verification fails (e.g. invalid token, wrong code)
|
|
319
320
|
*/
|
|
320
|
-
async verify(options, storeOptions) {
|
|
321
|
-
const tokenResponse = await this.#options.authClient.mfa.verify(options);
|
|
321
|
+
async verify(options, storeOptions, requestOptions) {
|
|
322
|
+
const tokenResponse = await this.#options.authClient.mfa.verify(options, requestOptions);
|
|
322
323
|
const audience = options.audience ?? this.#options.defaultAudience;
|
|
323
324
|
const existingStateData = await this.#options.stateStore.get(
|
|
324
325
|
this.#options.stateStoreIdentifier,
|
|
@@ -368,6 +369,12 @@ var ServerPasskeyClient = class {
|
|
|
368
369
|
*
|
|
369
370
|
* This method does not create a session; no state is persisted.
|
|
370
371
|
*
|
|
372
|
+
* On a confidential client this endpoint accepts `client_secret` as its only
|
|
373
|
+
* credential, so configure `clientSecret` on the `ServerClient`. It does not
|
|
374
|
+
* accept a private key JWT and is not served on the mTLS endpoint aliases, so a
|
|
375
|
+
* client configured with only `clientAssertionSigningKey` or only `useMtls` is
|
|
376
|
+
* rejected by Auth0. Public clients authenticate with `clientId` alone.
|
|
377
|
+
*
|
|
371
378
|
* @param options User profile data and optional realm/organization.
|
|
372
379
|
* @param storeOptions Optional options used to resolve the domain (resolver mode).
|
|
373
380
|
*
|
|
@@ -375,10 +382,10 @@ var ServerPasskeyClient = class {
|
|
|
375
382
|
*
|
|
376
383
|
* @returns A promise resolving to the signup challenge.
|
|
377
384
|
*/
|
|
378
|
-
async register(options, storeOptions) {
|
|
385
|
+
async register(options, storeOptions, requestOptions) {
|
|
379
386
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
380
387
|
const authClient = this.#options.getAuthClient(domain);
|
|
381
|
-
return authClient.passkey.register(options);
|
|
388
|
+
return authClient.passkey.register(options, requestOptions);
|
|
382
389
|
}
|
|
383
390
|
/**
|
|
384
391
|
* Requests a passkey login challenge for an existing user.
|
|
@@ -390,6 +397,9 @@ var ServerPasskeyClient = class {
|
|
|
390
397
|
*
|
|
391
398
|
* This method does not create a session; no state is persisted.
|
|
392
399
|
*
|
|
400
|
+
* Client authentication works the same way as {@link ServerPasskeyClient.register}:
|
|
401
|
+
* on a confidential client, only a `clientSecret` is accepted here.
|
|
402
|
+
*
|
|
393
403
|
* @param options Optional realm/organization configuration.
|
|
394
404
|
* @param storeOptions Optional options used to resolve the domain (resolver mode).
|
|
395
405
|
*
|
|
@@ -397,10 +407,10 @@ var ServerPasskeyClient = class {
|
|
|
397
407
|
*
|
|
398
408
|
* @returns A promise resolving to the login challenge.
|
|
399
409
|
*/
|
|
400
|
-
async challenge(options, storeOptions) {
|
|
410
|
+
async challenge(options, storeOptions, requestOptions) {
|
|
401
411
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
402
412
|
const authClient = this.#options.getAuthClient(domain);
|
|
403
|
-
return authClient.passkey.challenge(options);
|
|
413
|
+
return authClient.passkey.challenge(options, requestOptions);
|
|
404
414
|
}
|
|
405
415
|
/**
|
|
406
416
|
* Completes a passkey authentication flow (signup or login) by exchanging the
|
|
@@ -422,7 +432,7 @@ var ServerPasskeyClient = class {
|
|
|
422
432
|
*
|
|
423
433
|
* @returns A promise resolving to an object containing the authorizationDetails (when RAR was used).
|
|
424
434
|
*/
|
|
425
|
-
async getToken(options, storeOptions) {
|
|
435
|
+
async getToken(options, storeOptions, requestOptions) {
|
|
426
436
|
const scope = ensureOpenIdScope(options.scope ?? this.#options.defaultScope);
|
|
427
437
|
const audience = options.audience ?? this.#options.defaultAudience;
|
|
428
438
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
@@ -431,7 +441,7 @@ var ServerPasskeyClient = class {
|
|
|
431
441
|
...options,
|
|
432
442
|
scope,
|
|
433
443
|
audience
|
|
434
|
-
});
|
|
444
|
+
}, requestOptions);
|
|
435
445
|
const existingStateData = await this.#options.stateStore.get(this.#options.stateStoreIdentifier, storeOptions);
|
|
436
446
|
const stateData = updateStateData(audience ?? "default", existingStateData, tokenEndpointResponse, { domain });
|
|
437
447
|
await this.#options.stateStore.set(this.#options.stateStoreIdentifier, stateData, true, storeOptions);
|
|
@@ -464,9 +474,9 @@ var ServerDatabaseClient = class {
|
|
|
464
474
|
*
|
|
465
475
|
* @returns A promise resolving to the created user result with a normalized `id` field.
|
|
466
476
|
*/
|
|
467
|
-
async signUp(options, storeOptions) {
|
|
477
|
+
async signUp(options, storeOptions, requestOptions) {
|
|
468
478
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
469
|
-
return this.#options.getAuthClient(domain).database.signUp(options);
|
|
479
|
+
return this.#options.getAuthClient(domain).database.signUp(options, requestOptions);
|
|
470
480
|
}
|
|
471
481
|
/**
|
|
472
482
|
* Requests a password-change email for a database connection user.
|
|
@@ -482,9 +492,9 @@ var ServerDatabaseClient = class {
|
|
|
482
492
|
*
|
|
483
493
|
* @returns A promise resolving to the server's plain-text confirmation message.
|
|
484
494
|
*/
|
|
485
|
-
async changePassword(options, storeOptions) {
|
|
495
|
+
async changePassword(options, storeOptions, requestOptions) {
|
|
486
496
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
487
|
-
return this.#options.getAuthClient(domain).database.changePassword(options);
|
|
497
|
+
return this.#options.getAuthClient(domain).database.changePassword(options, requestOptions);
|
|
488
498
|
}
|
|
489
499
|
};
|
|
490
500
|
|
|
@@ -759,6 +769,7 @@ var ServerClient = class {
|
|
|
759
769
|
* Takes an URL, extract the Authorization Code flow query parameters and requests a token.
|
|
760
770
|
* @param url The URl from which the query params should be extracted to exchange for a token.
|
|
761
771
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
772
|
+
* @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the code-for-token exchange.
|
|
762
773
|
*
|
|
763
774
|
* @throws {MissingTransactionError} When no transaction was found.
|
|
764
775
|
* @throws {TokenByCodeError} If there was an issue requesting the access token.
|
|
@@ -766,8 +777,15 @@ var ServerClient = class {
|
|
|
766
777
|
* @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
|
|
767
778
|
*
|
|
768
779
|
* @returns A promise resolving to an object, containing the original appState (if present) and the authorizationDetails (when RAR was used).
|
|
780
|
+
*
|
|
781
|
+
* @remarks
|
|
782
|
+
* This method does not support the `fullResponse` opt-in in v1. It accepts
|
|
783
|
+
* `url` and `storeOptions` with no intermediate options object; adding
|
|
784
|
+
* `fullResponse` would require a new options parameter and is deferred to
|
|
785
|
+
* a later revision.
|
|
786
|
+
* TODO(#<issue-number>): add fullResponse overload to completeInteractiveLogin in a future minor.
|
|
769
787
|
*/
|
|
770
|
-
async completeInteractiveLogin(url, storeOptions) {
|
|
788
|
+
async completeInteractiveLogin(url, storeOptions, requestOptions) {
|
|
771
789
|
const transactionData = await this.#transactionStore.get(this.#transactionStoreIdentifier, storeOptions);
|
|
772
790
|
if (!transactionData) {
|
|
773
791
|
throw new MissingTransactionError();
|
|
@@ -778,7 +796,7 @@ var ServerClient = class {
|
|
|
778
796
|
// TransactionData.codeVerifier is optional only to accommodate magic-link transactions.
|
|
779
797
|
codeVerifier: transactionData.codeVerifier,
|
|
780
798
|
organization: transactionData.organization
|
|
781
|
-
});
|
|
799
|
+
}, requestOptions);
|
|
782
800
|
await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
|
|
783
801
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
784
802
|
const stateData = applySessionExpiryAtLogin(
|
|
@@ -842,14 +860,15 @@ var ServerClient = class {
|
|
|
842
860
|
* Takes an URL, extract the Authorization Code flow query parameters and requests a token.
|
|
843
861
|
* @param url The URl from which the query params should be extracted to exchange for a token.
|
|
844
862
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
863
|
+
* @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the code-for-token exchange.
|
|
845
864
|
*
|
|
846
865
|
* @throws {MissingTransactionError} When no transaction was found.
|
|
847
866
|
* @throws {TokenByCodeError} If there was an issue requesting the access token.
|
|
848
867
|
*
|
|
849
868
|
* @returns A promise resolving to an object, containing the original appState (if present).
|
|
850
869
|
*/
|
|
851
|
-
async completeLinkUser(url, storeOptions) {
|
|
852
|
-
const result = await this.completeInteractiveLogin(url, storeOptions);
|
|
870
|
+
async completeLinkUser(url, storeOptions, requestOptions) {
|
|
871
|
+
const result = await this.completeInteractiveLogin(url, storeOptions, requestOptions);
|
|
853
872
|
return {
|
|
854
873
|
appState: result.appState
|
|
855
874
|
};
|
|
@@ -905,43 +924,44 @@ var ServerClient = class {
|
|
|
905
924
|
* Takes an URL, extract the Authorization Code flow query parameters and requests a token.
|
|
906
925
|
* @param url The URl from which the query params should be extracted to exchange for a token.
|
|
907
926
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
927
|
+
* @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the code-for-token exchange.
|
|
908
928
|
*
|
|
909
929
|
* @throws {MissingTransactionError} When no transaction was found.
|
|
910
930
|
* @throws {TokenByCodeError} If there was an issue requesting the access token.
|
|
911
931
|
*
|
|
912
932
|
* @returns A promise resolving to an object, containing the original appState (if present).
|
|
913
933
|
*/
|
|
914
|
-
async completeUnlinkUser(url, storeOptions) {
|
|
915
|
-
const result = await this.completeInteractiveLogin(url, storeOptions);
|
|
934
|
+
async completeUnlinkUser(url, storeOptions, requestOptions) {
|
|
935
|
+
const result = await this.completeInteractiveLogin(url, storeOptions, requestOptions);
|
|
916
936
|
return {
|
|
917
937
|
appState: result.appState
|
|
918
938
|
};
|
|
919
939
|
}
|
|
920
|
-
|
|
921
|
-
* Logs in using Client-Initiated Backchannel Authentication.
|
|
922
|
-
*
|
|
923
|
-
* Using Client-Initiated Backchannel Authentication requires the feature to be enabled in the Auth0 dashboard.
|
|
924
|
-
* @see https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow
|
|
925
|
-
* @param options Options used to configure the backchannel login process.
|
|
926
|
-
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
927
|
-
*
|
|
928
|
-
* @throws {BackchannelAuthenticationError} If there was an issue when doing backchannel authentication.
|
|
929
|
-
* @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
|
|
930
|
-
*
|
|
931
|
-
* @returns A promise resolving to an object, containing the authorizationDetails (when RAR was used).
|
|
932
|
-
*/
|
|
933
|
-
async loginBackchannel(options, storeOptions) {
|
|
940
|
+
async loginBackchannel(options, storeOptions, requestOptions) {
|
|
934
941
|
const scope = ensureOpenIdScope(options.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
|
|
935
942
|
const domain = await this.#resolveDomain(storeOptions);
|
|
936
943
|
const authClient = this.#getAuthClient(domain);
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
944
|
+
let response;
|
|
945
|
+
let tokenEndpointResponse;
|
|
946
|
+
if (options.fullResponse) {
|
|
947
|
+
const authJsResult = await authClient.backchannelAuthentication({
|
|
948
|
+
bindingMessage: options.bindingMessage,
|
|
949
|
+
loginHint: options.loginHint,
|
|
950
|
+
authorizationParams: { ...options.authorizationParams, scope },
|
|
951
|
+
fullResponse: true
|
|
952
|
+
}, requestOptions);
|
|
953
|
+
tokenEndpointResponse = authJsResult.data;
|
|
954
|
+
response = authJsResult.response;
|
|
955
|
+
} else {
|
|
956
|
+
tokenEndpointResponse = await authClient.backchannelAuthentication({
|
|
957
|
+
bindingMessage: options.bindingMessage,
|
|
958
|
+
loginHint: options.loginHint,
|
|
959
|
+
authorizationParams: {
|
|
960
|
+
...options.authorizationParams,
|
|
961
|
+
scope
|
|
962
|
+
}
|
|
963
|
+
}, requestOptions);
|
|
964
|
+
}
|
|
945
965
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
946
966
|
const stateData = applySessionExpiryAtLogin(
|
|
947
967
|
updateStateData(this.#options.authorizationParams?.audience ?? "default", existingStateData, tokenEndpointResponse, {
|
|
@@ -950,9 +970,16 @@ var ServerClient = class {
|
|
|
950
970
|
tokenEndpointResponse.claims
|
|
951
971
|
);
|
|
952
972
|
await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
|
|
953
|
-
|
|
973
|
+
const result = {
|
|
954
974
|
authorizationDetails: tokenEndpointResponse.authorizationDetails
|
|
955
975
|
};
|
|
976
|
+
if (options.fullResponse) {
|
|
977
|
+
if (!response) {
|
|
978
|
+
throw new import_auth0_auth_js.MissingCapturedResponseError();
|
|
979
|
+
}
|
|
980
|
+
return { data: result, response };
|
|
981
|
+
}
|
|
982
|
+
return result;
|
|
956
983
|
}
|
|
957
984
|
/**
|
|
958
985
|
* Starts a passwordless flow by sending a one-time code (OTP) or a magic link.
|
|
@@ -975,6 +1002,7 @@ var ServerClient = class {
|
|
|
975
1002
|
*
|
|
976
1003
|
* @param options Discriminated start options.
|
|
977
1004
|
* @param storeOptions Optional options passed to the resolver / stores.
|
|
1005
|
+
* @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the `/passwordless/start` request.
|
|
978
1006
|
*
|
|
979
1007
|
* @throws {PasswordlessStartError} If the request fails, or if a magic link is requested without a `redirectUri`.
|
|
980
1008
|
*
|
|
@@ -991,22 +1019,28 @@ var ServerClient = class {
|
|
|
991
1019
|
* redirectUri: 'https://app.example.com/auth/callback',
|
|
992
1020
|
* });
|
|
993
1021
|
*/
|
|
994
|
-
async startPasswordless(options, storeOptions) {
|
|
1022
|
+
async startPasswordless(options, storeOptions, requestOptions) {
|
|
995
1023
|
const domain = await this.#resolveDomain(storeOptions);
|
|
996
1024
|
const authClient = this.#getAuthClient(domain);
|
|
997
1025
|
if (options.connection === "sms") {
|
|
998
|
-
await authClient.passwordless.sendSms(
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1026
|
+
await authClient.passwordless.sendSms(
|
|
1027
|
+
{
|
|
1028
|
+
phoneNumber: options.phoneNumber,
|
|
1029
|
+
language: options.language
|
|
1030
|
+
},
|
|
1031
|
+
requestOptions
|
|
1032
|
+
);
|
|
1002
1033
|
return;
|
|
1003
1034
|
}
|
|
1004
1035
|
if (options.send !== "link") {
|
|
1005
|
-
await authClient.passwordless.sendEmail(
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1036
|
+
await authClient.passwordless.sendEmail(
|
|
1037
|
+
{
|
|
1038
|
+
email: options.email,
|
|
1039
|
+
send: "code",
|
|
1040
|
+
language: options.language
|
|
1041
|
+
},
|
|
1042
|
+
requestOptions
|
|
1043
|
+
);
|
|
1010
1044
|
return;
|
|
1011
1045
|
}
|
|
1012
1046
|
if (!options.redirectUri || typeof options.redirectUri !== "string") {
|
|
@@ -1015,19 +1049,22 @@ var ServerClient = class {
|
|
|
1015
1049
|
const state = crypto.randomUUID();
|
|
1016
1050
|
const scope = ensureOpenIdScope(options.scope ?? this.#options.authorizationParams?.scope);
|
|
1017
1051
|
const audience = options.audience ?? this.#options.authorizationParams?.audience;
|
|
1018
|
-
await authClient.passwordless.sendEmail(
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1052
|
+
await authClient.passwordless.sendEmail(
|
|
1053
|
+
{
|
|
1054
|
+
email: options.email,
|
|
1055
|
+
send: "link",
|
|
1056
|
+
language: options.language,
|
|
1057
|
+
authParams: {
|
|
1058
|
+
...options.authParams,
|
|
1059
|
+
redirect_uri: options.redirectUri,
|
|
1060
|
+
response_type: "code",
|
|
1061
|
+
scope,
|
|
1062
|
+
...audience ? { audience } : {},
|
|
1063
|
+
state
|
|
1064
|
+
}
|
|
1065
|
+
},
|
|
1066
|
+
requestOptions
|
|
1067
|
+
);
|
|
1031
1068
|
const transactionState = {
|
|
1032
1069
|
audience,
|
|
1033
1070
|
domain,
|
|
@@ -1035,42 +1072,42 @@ var ServerClient = class {
|
|
|
1035
1072
|
};
|
|
1036
1073
|
await this.#transactionStore.set(this.#transactionStoreIdentifier, transactionState, false, storeOptions);
|
|
1037
1074
|
}
|
|
1038
|
-
|
|
1039
|
-
* Completes a passwordless OTP login and persists the resulting session.
|
|
1040
|
-
*
|
|
1041
|
-
* Discriminated on `connection` to mirror the `@auth0/nextjs-auth0` `passwordless.verify()`
|
|
1042
|
-
* surface. Non-redirect flow: no PKCE and no transaction store (mirrors
|
|
1043
|
-
* {@link ServerClient#loginBackchannel}). The `openid` scope is always ensured by this layer.
|
|
1044
|
-
*
|
|
1045
|
-
* Note: the state store is read-then-written; if your deployment performs concurrent
|
|
1046
|
-
* logins for the same session identifier, use a state store with atomic/serializable
|
|
1047
|
-
* writes to avoid last-write-wins races.
|
|
1048
|
-
*
|
|
1049
|
-
* @param options Discriminated completion options (`connection`, identifier, `verificationCode`).
|
|
1050
|
-
* @param storeOptions Optional options passed to the resolver / stores.
|
|
1051
|
-
*
|
|
1052
|
-
* @throws {PasswordlessVerifyError} If the code is invalid, expired, or rate-limited. When the
|
|
1053
|
-
* connection requires MFA, the server responds with `mfa_required`; narrow the thrown error
|
|
1054
|
-
* with `isMfaRequiredError(error)` to read `cause.mfa_token`.
|
|
1055
|
-
*
|
|
1056
|
-
* @returns A promise resolving to the authorizationDetails (when RAR was used).
|
|
1057
|
-
*/
|
|
1058
|
-
async completePasswordless(options, storeOptions) {
|
|
1075
|
+
async completePasswordless(options, storeOptions, requestOptions) {
|
|
1059
1076
|
const scope = ensureOpenIdScope(options.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
|
|
1060
1077
|
const audience = options.authorizationParams?.audience ?? this.#options.authorizationParams?.audience;
|
|
1061
1078
|
const domain = await this.#resolveDomain(storeOptions);
|
|
1062
1079
|
const authClient = this.#getAuthClient(domain);
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1080
|
+
let response;
|
|
1081
|
+
let tokenEndpointResponse;
|
|
1082
|
+
if (options.fullResponse) {
|
|
1083
|
+
const authJsResult = options.connection === "sms" ? await authClient.getTokenByPasswordlessSms({
|
|
1084
|
+
phoneNumber: options.phoneNumber,
|
|
1085
|
+
code: options.verificationCode,
|
|
1086
|
+
audience,
|
|
1087
|
+
scope,
|
|
1088
|
+
fullResponse: true
|
|
1089
|
+
}, requestOptions) : await authClient.getTokenByPasswordlessEmail({
|
|
1090
|
+
email: options.email,
|
|
1091
|
+
code: options.verificationCode,
|
|
1092
|
+
audience,
|
|
1093
|
+
scope,
|
|
1094
|
+
fullResponse: true
|
|
1095
|
+
}, requestOptions);
|
|
1096
|
+
tokenEndpointResponse = authJsResult.data;
|
|
1097
|
+
response = authJsResult.response;
|
|
1098
|
+
} else {
|
|
1099
|
+
tokenEndpointResponse = options.connection === "sms" ? await authClient.getTokenByPasswordlessSms({
|
|
1100
|
+
phoneNumber: options.phoneNumber,
|
|
1101
|
+
code: options.verificationCode,
|
|
1102
|
+
audience,
|
|
1103
|
+
scope
|
|
1104
|
+
}, requestOptions) : await authClient.getTokenByPasswordlessEmail({
|
|
1105
|
+
email: options.email,
|
|
1106
|
+
code: options.verificationCode,
|
|
1107
|
+
audience,
|
|
1108
|
+
scope
|
|
1109
|
+
}, requestOptions);
|
|
1110
|
+
}
|
|
1074
1111
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
1075
1112
|
const stateData = updateStateData(
|
|
1076
1113
|
this.#options.authorizationParams?.audience ?? "default",
|
|
@@ -1079,9 +1116,16 @@ var ServerClient = class {
|
|
|
1079
1116
|
{ domain }
|
|
1080
1117
|
);
|
|
1081
1118
|
await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
|
|
1082
|
-
|
|
1119
|
+
const result = {
|
|
1083
1120
|
authorizationDetails: tokenEndpointResponse.authorizationDetails
|
|
1084
1121
|
};
|
|
1122
|
+
if (options.fullResponse) {
|
|
1123
|
+
if (!response) {
|
|
1124
|
+
throw new import_auth0_auth_js.MissingCapturedResponseError();
|
|
1125
|
+
}
|
|
1126
|
+
return { data: result, response };
|
|
1127
|
+
}
|
|
1128
|
+
return result;
|
|
1085
1129
|
}
|
|
1086
1130
|
/**
|
|
1087
1131
|
* Completes a passwordless magic-link login and persists the resulting session.
|
|
@@ -1093,6 +1137,7 @@ var ServerClient = class {
|
|
|
1093
1137
|
*
|
|
1094
1138
|
* @param url The callback URL containing the authorization `code` and `state`.
|
|
1095
1139
|
* @param storeOptions Optional options passed to the resolver / stores.
|
|
1140
|
+
* @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the code exchange.
|
|
1096
1141
|
*
|
|
1097
1142
|
* @throws {MissingTransactionError} If no magic-link transaction was found.
|
|
1098
1143
|
* @throws {PasswordlessVerifyError} If the returned `state` is missing or does not match.
|
|
@@ -1103,7 +1148,7 @@ var ServerClient = class {
|
|
|
1103
1148
|
* @example
|
|
1104
1149
|
* const result = await serverClient.completePasswordlessMagicLink(callbackUrl, storeOptions);
|
|
1105
1150
|
*/
|
|
1106
|
-
async completePasswordlessMagicLink(url, storeOptions) {
|
|
1151
|
+
async completePasswordlessMagicLink(url, storeOptions, requestOptions) {
|
|
1107
1152
|
const transactionData = await this.#transactionStore.get(this.#transactionStoreIdentifier, storeOptions);
|
|
1108
1153
|
if (!transactionData) {
|
|
1109
1154
|
throw new MissingTransactionError();
|
|
@@ -1115,7 +1160,7 @@ var ServerClient = class {
|
|
|
1115
1160
|
}
|
|
1116
1161
|
const domain = transactionData.domain ?? await this.#resolveDomain(storeOptions);
|
|
1117
1162
|
const authClient = this.#getAuthClient(domain);
|
|
1118
|
-
const tokenEndpointResponse = await authClient.getTokenByMagicLinkCode(url, { expectedState });
|
|
1163
|
+
const tokenEndpointResponse = await authClient.getTokenByMagicLinkCode(url, { expectedState }, requestOptions);
|
|
1119
1164
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
1120
1165
|
const stateData = updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse, {
|
|
1121
1166
|
domain
|
|
@@ -1128,6 +1173,12 @@ var ServerClient = class {
|
|
|
1128
1173
|
}
|
|
1129
1174
|
/**
|
|
1130
1175
|
* Retrieves the user from the store, or undefined if no user found.
|
|
1176
|
+
*
|
|
1177
|
+
* This does not accept `RequestOptions`. It is a pure read from the state store and makes no
|
|
1178
|
+
* network call, so a per-request `signal`/`headers`/`customFetch` could not take effect. The
|
|
1179
|
+
* exclusion is deliberate: a parameter that can never do anything costs the public surface more
|
|
1180
|
+
* than the asymmetry with `getAccessToken`/`getAccessTokenForConnection`/`revokeRefreshToken` does.
|
|
1181
|
+
*
|
|
1131
1182
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
1132
1183
|
* @returns The user, or undefined if no user found in the store.
|
|
1133
1184
|
*/
|
|
@@ -1170,6 +1221,34 @@ var ServerClient = class {
|
|
|
1170
1221
|
return sessionData;
|
|
1171
1222
|
}
|
|
1172
1223
|
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Retrieves the OIDC UserInfo claims for a given access token.
|
|
1226
|
+
*
|
|
1227
|
+
* The access token must be supplied explicitly by the caller. This method does NOT read
|
|
1228
|
+
* the token from the session and does NOT trigger a refresh. The token must be accepted by
|
|
1229
|
+
* the `/userinfo` endpoint:
|
|
1230
|
+
* - Without Multi-Resource Refresh Tokens (MRRT): pass a default OIDC access token, one
|
|
1231
|
+
* obtained without an explicit `audience` parameter.
|
|
1232
|
+
* - With MRRT: tokens are audience-bound, so request the userinfo endpoint as the audience
|
|
1233
|
+
* (e.g. `https://<domain>/userinfo`) when obtaining the token. A token bound to a
|
|
1234
|
+
* different resource-server audience is rejected by `/userinfo`.
|
|
1235
|
+
*
|
|
1236
|
+
* `/userinfo` is a bearer-protected resource and requires no client authentication, so this
|
|
1237
|
+
* works for public clients: the supplied access token is the only credential used.
|
|
1238
|
+
*
|
|
1239
|
+
* @param options Options containing the access token and an optional expected subject
|
|
1240
|
+
* for OIDC subject-consistency validation.
|
|
1241
|
+
* @param storeOptions Optional store options, used to resolve the domain in resolver mode.
|
|
1242
|
+
* @param requestOptions Optional per-request options (signal, headers, customFetch) forwarded
|
|
1243
|
+
* to the underlying `/userinfo` request.
|
|
1244
|
+
* @throws {UserInfoError} When the `/userinfo` request fails or the subject check fails.
|
|
1245
|
+
* @returns A Promise resolving to the UserInfo claims.
|
|
1246
|
+
*/
|
|
1247
|
+
async getUserInfo(options, storeOptions, requestOptions) {
|
|
1248
|
+
const domain = await this.#resolveDomain(storeOptions);
|
|
1249
|
+
const authClient = this.#getAuthClient(domain);
|
|
1250
|
+
return authClient.getUserInfo(options, requestOptions);
|
|
1251
|
+
}
|
|
1173
1252
|
/**
|
|
1174
1253
|
* 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.
|
|
1175
1254
|
* Also updates the store when a new token was retrieved from Auth0.
|
|
@@ -1178,19 +1257,30 @@ var ServerClient = class {
|
|
|
1178
1257
|
* request an access token for that audience/scope (Multi-Resource Refresh Tokens). Tokens are cached per
|
|
1179
1258
|
* audience and scope combination.
|
|
1180
1259
|
*
|
|
1181
|
-
*
|
|
1260
|
+
* When `options.fullResponse` is `true`, the method returns an {@link ApiResponse} envelope containing both
|
|
1261
|
+
* the token set and the raw {@link Response} from the token endpoint. The cache is bypassed in this case,
|
|
1262
|
+
* forcing a refresh-token call even when a valid cached token exists, because the `Response` can only be
|
|
1263
|
+
* produced by a live HTTP call.
|
|
1264
|
+
*
|
|
1265
|
+
* @param options Optional options for requesting a specific audience/scope or enabling full response.
|
|
1182
1266
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
1267
|
+
* @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.
|
|
1268
|
+
*
|
|
1269
|
+
* @remarks
|
|
1270
|
+
* Legacy single-argument form: `getAccessToken(storeOptions?)`. If your `TStoreOptions` type
|
|
1271
|
+
* contains `audience` or `scope` keys, use the explicit two-argument form instead:
|
|
1272
|
+
* `getAccessToken({}, storeOptions)` to avoid call-site routing ambiguity.
|
|
1183
1273
|
*
|
|
1184
1274
|
* @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`.
|
|
1185
1275
|
* @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.
|
|
1186
1276
|
*
|
|
1187
|
-
* @returns The Token Set
|
|
1277
|
+
* @returns The Token Set when `fullResponse` is omitted, or an {@link ApiResponse} envelope when `fullResponse: true`.
|
|
1188
1278
|
*/
|
|
1189
|
-
async getAccessToken(tokenOptionsOrStoreOptions, storeOptions) {
|
|
1279
|
+
async getAccessToken(tokenOptionsOrStoreOptions, storeOptions, requestOptions) {
|
|
1190
1280
|
const hasTokenOptions = (
|
|
1191
1281
|
// If second arg exists, first arg must be GetAccessTokenOptions
|
|
1192
|
-
storeOptions !== void 0 || // OR if first arg has audience
|
|
1193
|
-
!!tokenOptionsOrStoreOptions && typeof tokenOptionsOrStoreOptions === "object" && ("audience" in tokenOptionsOrStoreOptions || "scope" in tokenOptionsOrStoreOptions)
|
|
1282
|
+
storeOptions !== void 0 || // OR if first arg has audience, scope, or fullResponse properties
|
|
1283
|
+
!!tokenOptionsOrStoreOptions && typeof tokenOptionsOrStoreOptions === "object" && ("audience" in tokenOptionsOrStoreOptions || "scope" in tokenOptionsOrStoreOptions || "fullResponse" in tokenOptionsOrStoreOptions)
|
|
1194
1284
|
);
|
|
1195
1285
|
const [resolvedOptions, resolvedStoreOptions] = hasTokenOptions ? [tokenOptionsOrStoreOptions, storeOptions] : [void 0, tokenOptionsOrStoreOptions];
|
|
1196
1286
|
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, resolvedStoreOptions);
|
|
@@ -1218,7 +1308,9 @@ var ServerClient = class {
|
|
|
1218
1308
|
(tokenSet2) => tokenSet2.audience === audience && (!scope || compareScopes(tokenSet2.scope, scope))
|
|
1219
1309
|
);
|
|
1220
1310
|
if (tokenSet && tokenSet.expiresAt > Date.now() / 1e3) {
|
|
1221
|
-
|
|
1311
|
+
if (!resolvedOptions?.fullResponse) {
|
|
1312
|
+
return tokenSet;
|
|
1313
|
+
}
|
|
1222
1314
|
}
|
|
1223
1315
|
if (!stateData?.refreshToken) {
|
|
1224
1316
|
throw new import_auth0_auth_js.TokenByRefreshTokenError(
|
|
@@ -1235,35 +1327,38 @@ var ServerClient = class {
|
|
|
1235
1327
|
...scope && { scope }
|
|
1236
1328
|
}
|
|
1237
1329
|
};
|
|
1238
|
-
|
|
1330
|
+
let response;
|
|
1331
|
+
let tokenEndpointResponse;
|
|
1332
|
+
if (resolvedOptions?.fullResponse) {
|
|
1333
|
+
const authJsResult = await this.#getAuthClient(domainForSession).getTokenByRefreshToken({
|
|
1334
|
+
...tokenByRefreshTokenOptions,
|
|
1335
|
+
fullResponse: true
|
|
1336
|
+
}, requestOptions);
|
|
1337
|
+
tokenEndpointResponse = authJsResult.data;
|
|
1338
|
+
response = authJsResult.response;
|
|
1339
|
+
} else {
|
|
1340
|
+
tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenByRefreshToken(tokenByRefreshTokenOptions, requestOptions);
|
|
1341
|
+
}
|
|
1239
1342
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, resolvedStoreOptions);
|
|
1240
1343
|
const updatedStateData = updateStateData(audience, existingStateData, tokenEndpointResponse, {
|
|
1241
1344
|
domain: domainForSession
|
|
1242
1345
|
});
|
|
1243
1346
|
await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, resolvedStoreOptions);
|
|
1244
|
-
|
|
1347
|
+
const returnTokenSet = {
|
|
1245
1348
|
accessToken: tokenEndpointResponse.accessToken,
|
|
1246
1349
|
scope: tokenEndpointResponse.scope,
|
|
1247
1350
|
expiresAt: tokenEndpointResponse.expiresAt,
|
|
1248
1351
|
audience
|
|
1249
1352
|
};
|
|
1353
|
+
if (resolvedOptions?.fullResponse) {
|
|
1354
|
+
if (!response) {
|
|
1355
|
+
throw new import_auth0_auth_js.MissingCapturedResponseError();
|
|
1356
|
+
}
|
|
1357
|
+
return { data: returnTokenSet, response };
|
|
1358
|
+
}
|
|
1359
|
+
return returnTokenSet;
|
|
1250
1360
|
}
|
|
1251
|
-
|
|
1252
|
-
* Retrieves an access token for a connection.
|
|
1253
|
-
*
|
|
1254
|
-
* This method attempts to obtain an access token for a specified connection.
|
|
1255
|
-
* It first checks if a refresh token exists in the store.
|
|
1256
|
-
* If no refresh token is found, it throws an `AccessTokenForConnectionError` indicating
|
|
1257
|
-
* that the refresh token was not found.
|
|
1258
|
-
*
|
|
1259
|
-
* @param options - Options for retrieving an access token for a connection.
|
|
1260
|
-
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
1261
|
-
*
|
|
1262
|
-
* @throws {TokenForConnectionError} If the refresh token was not found or there was an issue requesting the access token.
|
|
1263
|
-
*
|
|
1264
|
-
* @returns The Connection Token Set, containing the access token for the connection, as well as additional information.
|
|
1265
|
-
*/
|
|
1266
|
-
async getAccessTokenForConnection(options, storeOptions) {
|
|
1361
|
+
async getAccessTokenForConnection(options, storeOptions, requestOptions) {
|
|
1267
1362
|
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
1268
1363
|
const sessionDomain = stateData ? this.#getSessionDomain(stateData) : this.#staticDomain;
|
|
1269
1364
|
if (this.#isResolverMode()) {
|
|
@@ -1282,7 +1377,9 @@ var ServerClient = class {
|
|
|
1282
1377
|
(tokenSet) => tokenSet.connection === options.connection
|
|
1283
1378
|
);
|
|
1284
1379
|
if (connectionTokenSet && connectionTokenSet.expiresAt > Date.now() / 1e3) {
|
|
1285
|
-
|
|
1380
|
+
if (!options.fullResponse) {
|
|
1381
|
+
return connectionTokenSet;
|
|
1382
|
+
}
|
|
1286
1383
|
}
|
|
1287
1384
|
if (!stateData?.refreshToken) {
|
|
1288
1385
|
throw new import_auth0_auth_js.TokenForConnectionError(
|
|
@@ -1290,11 +1387,24 @@ var ServerClient = class {
|
|
|
1290
1387
|
);
|
|
1291
1388
|
}
|
|
1292
1389
|
const domainForSession = sessionDomain;
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1390
|
+
let response;
|
|
1391
|
+
let tokenEndpointResponse;
|
|
1392
|
+
if (options.fullResponse) {
|
|
1393
|
+
const authJsResult = await this.#getAuthClient(domainForSession).getTokenForConnection({
|
|
1394
|
+
connection: options.connection,
|
|
1395
|
+
loginHint: options.loginHint,
|
|
1396
|
+
refreshToken: stateData.refreshToken,
|
|
1397
|
+
fullResponse: true
|
|
1398
|
+
}, requestOptions);
|
|
1399
|
+
tokenEndpointResponse = authJsResult.data;
|
|
1400
|
+
response = authJsResult.response;
|
|
1401
|
+
} else {
|
|
1402
|
+
tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenForConnection({
|
|
1403
|
+
connection: options.connection,
|
|
1404
|
+
loginHint: options.loginHint,
|
|
1405
|
+
refreshToken: stateData.refreshToken
|
|
1406
|
+
}, requestOptions);
|
|
1407
|
+
}
|
|
1298
1408
|
const updatedStateData = updateStateDataForConnectionTokenSet(
|
|
1299
1409
|
options,
|
|
1300
1410
|
{
|
|
@@ -1304,13 +1414,20 @@ var ServerClient = class {
|
|
|
1304
1414
|
tokenEndpointResponse
|
|
1305
1415
|
);
|
|
1306
1416
|
await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, storeOptions);
|
|
1307
|
-
|
|
1417
|
+
const returnConnectionTokenSet = {
|
|
1308
1418
|
accessToken: tokenEndpointResponse.accessToken,
|
|
1309
1419
|
scope: tokenEndpointResponse.scope,
|
|
1310
1420
|
expiresAt: tokenEndpointResponse.expiresAt,
|
|
1311
1421
|
connection: options.connection,
|
|
1312
1422
|
loginHint: options.loginHint
|
|
1313
1423
|
};
|
|
1424
|
+
if (options.fullResponse) {
|
|
1425
|
+
if (!response) {
|
|
1426
|
+
throw new import_auth0_auth_js.MissingCapturedResponseError();
|
|
1427
|
+
}
|
|
1428
|
+
return { data: returnConnectionTokenSet, response };
|
|
1429
|
+
}
|
|
1430
|
+
return returnConnectionTokenSet;
|
|
1314
1431
|
}
|
|
1315
1432
|
/**
|
|
1316
1433
|
* Revokes the refresh token stored in the current session, or an explicitly supplied token.
|
|
@@ -1322,12 +1439,13 @@ var ServerClient = class {
|
|
|
1322
1439
|
*
|
|
1323
1440
|
* @param options Optionally supply a token to revoke instead of reading from the session.
|
|
1324
1441
|
* @param storeOptions Optional options passed to the StateStore.
|
|
1442
|
+
* @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the revocation request.
|
|
1325
1443
|
*
|
|
1326
1444
|
* @throws {MissingRequiredArgumentError} If `options.token` is an empty string.
|
|
1327
1445
|
* @throws {MissingSessionError} If no refresh token is found in the session and none was provided.
|
|
1328
1446
|
* @throws {TokenRevocationError} If the revocation request fails.
|
|
1329
1447
|
*/
|
|
1330
|
-
async revokeRefreshToken(options = {}, storeOptions) {
|
|
1448
|
+
async revokeRefreshToken(options = {}, storeOptions, requestOptions) {
|
|
1331
1449
|
if (options.token !== void 0 && options.token.length === 0) {
|
|
1332
1450
|
throw new MissingRequiredArgumentError("options.token must not be an empty string.");
|
|
1333
1451
|
}
|
|
@@ -1351,18 +1469,19 @@ var ServerClient = class {
|
|
|
1351
1469
|
} else {
|
|
1352
1470
|
authClient = this.authClient;
|
|
1353
1471
|
}
|
|
1354
|
-
await authClient.revokeToken({ token: refreshToken, tokenTypeHint: "refresh_token" });
|
|
1472
|
+
await authClient.revokeToken({ token: refreshToken, tokenTypeHint: "refresh_token" }, requestOptions);
|
|
1355
1473
|
}
|
|
1356
1474
|
/**
|
|
1357
1475
|
* Logs the user out and returns a URL to redirect the user-agent to after they log out.
|
|
1358
1476
|
* @param options Options used to configure the logout process.
|
|
1359
1477
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
1478
|
+
* @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.
|
|
1360
1479
|
* @returns {URL}
|
|
1361
1480
|
*/
|
|
1362
|
-
async logout(options, storeOptions) {
|
|
1481
|
+
async logout(options, storeOptions, requestOptions) {
|
|
1363
1482
|
if (!this.#isResolverMode()) {
|
|
1364
1483
|
try {
|
|
1365
|
-
await this.revokeRefreshToken({}, storeOptions);
|
|
1484
|
+
await this.revokeRefreshToken({}, storeOptions, requestOptions);
|
|
1366
1485
|
} catch {
|
|
1367
1486
|
}
|
|
1368
1487
|
await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
|
|
@@ -1378,39 +1497,33 @@ var ServerClient = class {
|
|
|
1378
1497
|
const domainMatches = sessionDomain === resolvedDomain;
|
|
1379
1498
|
if (domainMatches) {
|
|
1380
1499
|
try {
|
|
1381
|
-
await this.revokeRefreshToken({}, storeOptions);
|
|
1500
|
+
await this.revokeRefreshToken({}, storeOptions, requestOptions);
|
|
1382
1501
|
} catch {
|
|
1383
1502
|
}
|
|
1384
1503
|
await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
|
|
1385
1504
|
}
|
|
1386
1505
|
return authClient.buildLogoutUrl(options);
|
|
1387
1506
|
}
|
|
1388
|
-
|
|
1389
|
-
* Exchanges a custom token for Auth0 tokens and persists the resulting session (RFC 8693).
|
|
1390
|
-
*
|
|
1391
|
-
* Calls the token endpoint using the RFC 8693 Token Exchange grant, then stores the
|
|
1392
|
-
* resulting tokens in the StateStore — effectively logging the user in without an
|
|
1393
|
-
* interactive browser flow. Use this when the caller already holds a trusted external
|
|
1394
|
-
* token (e.g. a Google ID token, a legacy system token) and wants to establish an
|
|
1395
|
-
* Auth0 session from it.
|
|
1396
|
-
*
|
|
1397
|
-
* Requires a Token Exchange Profile configured in your Auth0 tenant.
|
|
1398
|
-
*
|
|
1399
|
-
* @param options Options for the custom token exchange, including the subject token and its type.
|
|
1400
|
-
* @param storeOptions Optional options passed to the StateStore.
|
|
1401
|
-
*
|
|
1402
|
-
* @throws {TokenExchangeError} If the exchange fails or the subject token is invalid.
|
|
1403
|
-
* @throws {MissingClientAuthError} If client credentials are not configured.
|
|
1404
|
-
*
|
|
1405
|
-
* @returns A promise resolving to an object containing `authorizationDetails` when RAR was used.
|
|
1406
|
-
*/
|
|
1407
|
-
async loginWithCustomTokenExchange(options, storeOptions) {
|
|
1507
|
+
async loginWithCustomTokenExchange(options, storeOptions, requestOptions) {
|
|
1408
1508
|
const domain = await this.#resolveDomain(storeOptions);
|
|
1409
1509
|
const authClient = this.#getAuthClient(domain);
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1510
|
+
let response;
|
|
1511
|
+
let tokenEndpointResponse;
|
|
1512
|
+
if (options.fullResponse) {
|
|
1513
|
+
const { fullResponse: _, ...rest } = options;
|
|
1514
|
+
const authJsResult = await authClient.exchangeToken({
|
|
1515
|
+
...rest,
|
|
1516
|
+
scope: ensureOpenIdScope(options.scope),
|
|
1517
|
+
fullResponse: true
|
|
1518
|
+
}, requestOptions);
|
|
1519
|
+
tokenEndpointResponse = authJsResult.data;
|
|
1520
|
+
response = authJsResult.response;
|
|
1521
|
+
} else {
|
|
1522
|
+
tokenEndpointResponse = await authClient.exchangeToken({
|
|
1523
|
+
...options,
|
|
1524
|
+
scope: ensureOpenIdScope(options.scope)
|
|
1525
|
+
}, requestOptions);
|
|
1526
|
+
}
|
|
1414
1527
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
1415
1528
|
const stateData = updateStateData(
|
|
1416
1529
|
this.#options.authorizationParams?.audience ?? "default",
|
|
@@ -1419,30 +1532,25 @@ var ServerClient = class {
|
|
|
1419
1532
|
{ domain }
|
|
1420
1533
|
);
|
|
1421
1534
|
await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
|
|
1422
|
-
|
|
1535
|
+
const result = {
|
|
1536
|
+
authorizationDetails: tokenEndpointResponse.authorizationDetails
|
|
1537
|
+
};
|
|
1538
|
+
if (options.fullResponse) {
|
|
1539
|
+
if (!response) {
|
|
1540
|
+
throw new import_auth0_auth_js.MissingCapturedResponseError();
|
|
1541
|
+
}
|
|
1542
|
+
return { data: result, response };
|
|
1543
|
+
}
|
|
1544
|
+
return result;
|
|
1423
1545
|
}
|
|
1424
|
-
|
|
1425
|
-
* Exchanges a custom token for Auth0 tokens without establishing a session (RFC 8693).
|
|
1426
|
-
*
|
|
1427
|
-
* Performs the same RFC 8693 Token Exchange as `loginWithCustomTokenExchange` but
|
|
1428
|
-
* returns the raw token response without writing anything to the StateStore. Use this
|
|
1429
|
-
* for delegation or impersonation flows where you need downstream tokens but do not
|
|
1430
|
-
* want to create or modify the current user session.
|
|
1431
|
-
*
|
|
1432
|
-
* Requires a Token Exchange Profile configured in your Auth0 tenant.
|
|
1433
|
-
*
|
|
1434
|
-
* @param options Options for the custom token exchange, including the subject token and its type.
|
|
1435
|
-
* @param storeOptions Optional options passed to the StateStore (used only for domain resolution in resolver mode).
|
|
1436
|
-
*
|
|
1437
|
-
* @throws {TokenExchangeError} If the exchange fails or the subject token is invalid.
|
|
1438
|
-
* @throws {MissingClientAuthError} If client credentials are not configured.
|
|
1439
|
-
*
|
|
1440
|
-
* @returns A promise resolving to the token response from Auth0.
|
|
1441
|
-
*/
|
|
1442
|
-
async customTokenExchange(options, storeOptions) {
|
|
1546
|
+
async customTokenExchange(options, storeOptions, requestOptions) {
|
|
1443
1547
|
const domain = await this.#resolveDomain(storeOptions);
|
|
1444
1548
|
const authClient = this.#getAuthClient(domain);
|
|
1445
|
-
|
|
1549
|
+
if (options.fullResponse) {
|
|
1550
|
+
const { fullResponse: _, ...rest } = options;
|
|
1551
|
+
return authClient.exchangeToken({ ...rest, fullResponse: true }, requestOptions);
|
|
1552
|
+
}
|
|
1553
|
+
return authClient.exchangeToken(options, requestOptions);
|
|
1446
1554
|
}
|
|
1447
1555
|
/**
|
|
1448
1556
|
* Requests a Session Transfer Token (STT) for impersonation via session transfer (RFC 8693).
|
|
@@ -1466,8 +1574,17 @@ var ServerClient = class {
|
|
|
1466
1574
|
* {@link ServerClient.buildSessionTransferRedirect}, which is forwarded to the target's
|
|
1467
1575
|
* `/authorize` on the redirect.
|
|
1468
1576
|
*
|
|
1577
|
+
* @remarks
|
|
1578
|
+
* If the actor's ID token has expired, an internal refresh is performed before the
|
|
1579
|
+
* session transfer token exchange. This refresh call is NOT guarded by the caller's
|
|
1580
|
+
* requestOptions.signal — if the signal fires during this step, the abort is ignored.
|
|
1581
|
+
* Only the final exchangeToken call respects the signal.
|
|
1582
|
+
* Thread requestOptions into #resolveSessionTransferActor in a future minor if
|
|
1583
|
+
* callers need full-request abort coverage.
|
|
1584
|
+
*
|
|
1469
1585
|
* @param options Options including the developer-supplied `subjectToken`/`subjectTokenType` and an optional explicit `actor`.
|
|
1470
1586
|
* @param storeOptions Optional options used to read the agent session (for the actor) and resolve the request domain.
|
|
1587
|
+
* @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.
|
|
1471
1588
|
*
|
|
1472
1589
|
* @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.
|
|
1473
1590
|
* @throws {MissingClientAuthError} When client credentials are not configured (STT requires a confidential client).
|
|
@@ -1476,7 +1593,7 @@ var ServerClient = class {
|
|
|
1476
1593
|
*
|
|
1477
1594
|
* @returns A promise resolving to a {@link SessionTransferTokenResult} containing the STT and its metadata.
|
|
1478
1595
|
*/
|
|
1479
|
-
async requestSessionTransferToken(options, storeOptions) {
|
|
1596
|
+
async requestSessionTransferToken(options, storeOptions, requestOptions) {
|
|
1480
1597
|
if (!options.subjectToken || !options.subjectToken.trim()) {
|
|
1481
1598
|
throw new MissingRequiredArgumentError("subjectToken");
|
|
1482
1599
|
}
|
|
@@ -1502,7 +1619,7 @@ var ServerClient = class {
|
|
|
1502
1619
|
// `/authorize`; neither implies the other.
|
|
1503
1620
|
organization: options.organization,
|
|
1504
1621
|
extra: options.extra
|
|
1505
|
-
});
|
|
1622
|
+
}, requestOptions);
|
|
1506
1623
|
return {
|
|
1507
1624
|
sessionTransferToken: response.accessToken,
|
|
1508
1625
|
// Surface exactly what the server returned — never fabricate the URN, so a non-STT
|
|
@@ -1626,6 +1743,11 @@ var ServerClient = class {
|
|
|
1626
1743
|
}
|
|
1627
1744
|
/**
|
|
1628
1745
|
* Handles the backchannel logout process by verifying the logout token and deleting the session from the store if the logout token was considered valid.
|
|
1746
|
+
*
|
|
1747
|
+
* This does not accept `RequestOptions`. Verification does fetch JWKS, but the auth-js method it
|
|
1748
|
+
* delegates to, `verifyLogoutToken`, takes no `requestOptions`, so there is nothing to forward.
|
|
1749
|
+
* That fetch always uses the client's configured `customFetch`.
|
|
1750
|
+
*
|
|
1629
1751
|
* @param logoutToken The logout token to verify and use to delete the session from the store.
|
|
1630
1752
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
1631
1753
|
*
|
|
@@ -2017,6 +2139,7 @@ var import_auth0_auth_js4 = require("@auth0/auth0-auth-js");
|
|
|
2017
2139
|
TokenExchangeError,
|
|
2018
2140
|
TokenExchangeErrorCode,
|
|
2019
2141
|
TokenRevocationError,
|
|
2142
|
+
UserInfoError,
|
|
2020
2143
|
isMfaRequiredError
|
|
2021
2144
|
});
|
|
2022
2145
|
//# sourceMappingURL=index.cjs.map
|