@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.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.
|
|
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,
|
|
@@ -317,6 +318,12 @@ var ServerPasskeyClient = class {
|
|
|
317
318
|
*
|
|
318
319
|
* This method does not create a session; no state is persisted.
|
|
319
320
|
*
|
|
321
|
+
* On a confidential client this endpoint accepts `client_secret` as its only
|
|
322
|
+
* credential, so configure `clientSecret` on the `ServerClient`. It does not
|
|
323
|
+
* accept a private key JWT and is not served on the mTLS endpoint aliases, so a
|
|
324
|
+
* client configured with only `clientAssertionSigningKey` or only `useMtls` is
|
|
325
|
+
* rejected by Auth0. Public clients authenticate with `clientId` alone.
|
|
326
|
+
*
|
|
320
327
|
* @param options User profile data and optional realm/organization.
|
|
321
328
|
* @param storeOptions Optional options used to resolve the domain (resolver mode).
|
|
322
329
|
*
|
|
@@ -324,10 +331,10 @@ var ServerPasskeyClient = class {
|
|
|
324
331
|
*
|
|
325
332
|
* @returns A promise resolving to the signup challenge.
|
|
326
333
|
*/
|
|
327
|
-
async register(options, storeOptions) {
|
|
334
|
+
async register(options, storeOptions, requestOptions) {
|
|
328
335
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
329
336
|
const authClient = this.#options.getAuthClient(domain);
|
|
330
|
-
return authClient.passkey.register(options);
|
|
337
|
+
return authClient.passkey.register(options, requestOptions);
|
|
331
338
|
}
|
|
332
339
|
/**
|
|
333
340
|
* Requests a passkey login challenge for an existing user.
|
|
@@ -339,6 +346,9 @@ var ServerPasskeyClient = class {
|
|
|
339
346
|
*
|
|
340
347
|
* This method does not create a session; no state is persisted.
|
|
341
348
|
*
|
|
349
|
+
* Client authentication works the same way as {@link ServerPasskeyClient.register}:
|
|
350
|
+
* on a confidential client, only a `clientSecret` is accepted here.
|
|
351
|
+
*
|
|
342
352
|
* @param options Optional realm/organization configuration.
|
|
343
353
|
* @param storeOptions Optional options used to resolve the domain (resolver mode).
|
|
344
354
|
*
|
|
@@ -346,10 +356,10 @@ var ServerPasskeyClient = class {
|
|
|
346
356
|
*
|
|
347
357
|
* @returns A promise resolving to the login challenge.
|
|
348
358
|
*/
|
|
349
|
-
async challenge(options, storeOptions) {
|
|
359
|
+
async challenge(options, storeOptions, requestOptions) {
|
|
350
360
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
351
361
|
const authClient = this.#options.getAuthClient(domain);
|
|
352
|
-
return authClient.passkey.challenge(options);
|
|
362
|
+
return authClient.passkey.challenge(options, requestOptions);
|
|
353
363
|
}
|
|
354
364
|
/**
|
|
355
365
|
* Completes a passkey authentication flow (signup or login) by exchanging the
|
|
@@ -371,7 +381,7 @@ var ServerPasskeyClient = class {
|
|
|
371
381
|
*
|
|
372
382
|
* @returns A promise resolving to an object containing the authorizationDetails (when RAR was used).
|
|
373
383
|
*/
|
|
374
|
-
async getToken(options, storeOptions) {
|
|
384
|
+
async getToken(options, storeOptions, requestOptions) {
|
|
375
385
|
const scope = ensureOpenIdScope(options.scope ?? this.#options.defaultScope);
|
|
376
386
|
const audience = options.audience ?? this.#options.defaultAudience;
|
|
377
387
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
@@ -380,7 +390,7 @@ var ServerPasskeyClient = class {
|
|
|
380
390
|
...options,
|
|
381
391
|
scope,
|
|
382
392
|
audience
|
|
383
|
-
});
|
|
393
|
+
}, requestOptions);
|
|
384
394
|
const existingStateData = await this.#options.stateStore.get(this.#options.stateStoreIdentifier, storeOptions);
|
|
385
395
|
const stateData = updateStateData(audience ?? "default", existingStateData, tokenEndpointResponse, { domain });
|
|
386
396
|
await this.#options.stateStore.set(this.#options.stateStoreIdentifier, stateData, true, storeOptions);
|
|
@@ -413,9 +423,9 @@ var ServerDatabaseClient = class {
|
|
|
413
423
|
*
|
|
414
424
|
* @returns A promise resolving to the created user result with a normalized `id` field.
|
|
415
425
|
*/
|
|
416
|
-
async signUp(options, storeOptions) {
|
|
426
|
+
async signUp(options, storeOptions, requestOptions) {
|
|
417
427
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
418
|
-
return this.#options.getAuthClient(domain).database.signUp(options);
|
|
428
|
+
return this.#options.getAuthClient(domain).database.signUp(options, requestOptions);
|
|
419
429
|
}
|
|
420
430
|
/**
|
|
421
431
|
* Requests a password-change email for a database connection user.
|
|
@@ -431,9 +441,9 @@ var ServerDatabaseClient = class {
|
|
|
431
441
|
*
|
|
432
442
|
* @returns A promise resolving to the server's plain-text confirmation message.
|
|
433
443
|
*/
|
|
434
|
-
async changePassword(options, storeOptions) {
|
|
444
|
+
async changePassword(options, storeOptions, requestOptions) {
|
|
435
445
|
const domain = await this.#options.resolveDomain(storeOptions);
|
|
436
|
-
return this.#options.getAuthClient(domain).database.changePassword(options);
|
|
446
|
+
return this.#options.getAuthClient(domain).database.changePassword(options, requestOptions);
|
|
437
447
|
}
|
|
438
448
|
};
|
|
439
449
|
|
|
@@ -708,6 +718,7 @@ var ServerClient = class {
|
|
|
708
718
|
* Takes an URL, extract the Authorization Code flow query parameters and requests a token.
|
|
709
719
|
* @param url The URl from which the query params should be extracted to exchange for a token.
|
|
710
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.
|
|
711
722
|
*
|
|
712
723
|
* @throws {MissingTransactionError} When no transaction was found.
|
|
713
724
|
* @throws {TokenByCodeError} If there was an issue requesting the access token.
|
|
@@ -715,8 +726,15 @@ var ServerClient = class {
|
|
|
715
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.
|
|
716
727
|
*
|
|
717
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.
|
|
718
736
|
*/
|
|
719
|
-
async completeInteractiveLogin(url, storeOptions) {
|
|
737
|
+
async completeInteractiveLogin(url, storeOptions, requestOptions) {
|
|
720
738
|
const transactionData = await this.#transactionStore.get(this.#transactionStoreIdentifier, storeOptions);
|
|
721
739
|
if (!transactionData) {
|
|
722
740
|
throw new MissingTransactionError();
|
|
@@ -727,7 +745,7 @@ var ServerClient = class {
|
|
|
727
745
|
// TransactionData.codeVerifier is optional only to accommodate magic-link transactions.
|
|
728
746
|
codeVerifier: transactionData.codeVerifier,
|
|
729
747
|
organization: transactionData.organization
|
|
730
|
-
});
|
|
748
|
+
}, requestOptions);
|
|
731
749
|
await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
|
|
732
750
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
733
751
|
const stateData = applySessionExpiryAtLogin(
|
|
@@ -791,14 +809,15 @@ var ServerClient = class {
|
|
|
791
809
|
* Takes an URL, extract the Authorization Code flow query parameters and requests a token.
|
|
792
810
|
* @param url The URl from which the query params should be extracted to exchange for a token.
|
|
793
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.
|
|
794
813
|
*
|
|
795
814
|
* @throws {MissingTransactionError} When no transaction was found.
|
|
796
815
|
* @throws {TokenByCodeError} If there was an issue requesting the access token.
|
|
797
816
|
*
|
|
798
817
|
* @returns A promise resolving to an object, containing the original appState (if present).
|
|
799
818
|
*/
|
|
800
|
-
async completeLinkUser(url, storeOptions) {
|
|
801
|
-
const result = await this.completeInteractiveLogin(url, storeOptions);
|
|
819
|
+
async completeLinkUser(url, storeOptions, requestOptions) {
|
|
820
|
+
const result = await this.completeInteractiveLogin(url, storeOptions, requestOptions);
|
|
802
821
|
return {
|
|
803
822
|
appState: result.appState
|
|
804
823
|
};
|
|
@@ -854,43 +873,44 @@ var ServerClient = class {
|
|
|
854
873
|
* Takes an URL, extract the Authorization Code flow query parameters and requests a token.
|
|
855
874
|
* @param url The URl from which the query params should be extracted to exchange for a token.
|
|
856
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.
|
|
857
877
|
*
|
|
858
878
|
* @throws {MissingTransactionError} When no transaction was found.
|
|
859
879
|
* @throws {TokenByCodeError} If there was an issue requesting the access token.
|
|
860
880
|
*
|
|
861
881
|
* @returns A promise resolving to an object, containing the original appState (if present).
|
|
862
882
|
*/
|
|
863
|
-
async completeUnlinkUser(url, storeOptions) {
|
|
864
|
-
const result = await this.completeInteractiveLogin(url, storeOptions);
|
|
883
|
+
async completeUnlinkUser(url, storeOptions, requestOptions) {
|
|
884
|
+
const result = await this.completeInteractiveLogin(url, storeOptions, requestOptions);
|
|
865
885
|
return {
|
|
866
886
|
appState: result.appState
|
|
867
887
|
};
|
|
868
888
|
}
|
|
869
|
-
|
|
870
|
-
* Logs in using Client-Initiated Backchannel Authentication.
|
|
871
|
-
*
|
|
872
|
-
* Using Client-Initiated Backchannel Authentication requires the feature to be enabled in the Auth0 dashboard.
|
|
873
|
-
* @see https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow
|
|
874
|
-
* @param options Options used to configure the backchannel login process.
|
|
875
|
-
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
876
|
-
*
|
|
877
|
-
* @throws {BackchannelAuthenticationError} If there was an issue when doing backchannel authentication.
|
|
878
|
-
* @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
|
|
879
|
-
*
|
|
880
|
-
* @returns A promise resolving to an object, containing the authorizationDetails (when RAR was used).
|
|
881
|
-
*/
|
|
882
|
-
async loginBackchannel(options, storeOptions) {
|
|
889
|
+
async loginBackchannel(options, storeOptions, requestOptions) {
|
|
883
890
|
const scope = ensureOpenIdScope(options.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
|
|
884
891
|
const domain = await this.#resolveDomain(storeOptions);
|
|
885
892
|
const authClient = this.#getAuthClient(domain);
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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
|
+
}
|
|
894
914
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
895
915
|
const stateData = applySessionExpiryAtLogin(
|
|
896
916
|
updateStateData(this.#options.authorizationParams?.audience ?? "default", existingStateData, tokenEndpointResponse, {
|
|
@@ -899,9 +919,16 @@ var ServerClient = class {
|
|
|
899
919
|
tokenEndpointResponse.claims
|
|
900
920
|
);
|
|
901
921
|
await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
|
|
902
|
-
|
|
922
|
+
const result = {
|
|
903
923
|
authorizationDetails: tokenEndpointResponse.authorizationDetails
|
|
904
924
|
};
|
|
925
|
+
if (options.fullResponse) {
|
|
926
|
+
if (!response) {
|
|
927
|
+
throw new MissingCapturedResponseError();
|
|
928
|
+
}
|
|
929
|
+
return { data: result, response };
|
|
930
|
+
}
|
|
931
|
+
return result;
|
|
905
932
|
}
|
|
906
933
|
/**
|
|
907
934
|
* Starts a passwordless flow by sending a one-time code (OTP) or a magic link.
|
|
@@ -924,6 +951,7 @@ var ServerClient = class {
|
|
|
924
951
|
*
|
|
925
952
|
* @param options Discriminated start options.
|
|
926
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.
|
|
927
955
|
*
|
|
928
956
|
* @throws {PasswordlessStartError} If the request fails, or if a magic link is requested without a `redirectUri`.
|
|
929
957
|
*
|
|
@@ -940,22 +968,28 @@ var ServerClient = class {
|
|
|
940
968
|
* redirectUri: 'https://app.example.com/auth/callback',
|
|
941
969
|
* });
|
|
942
970
|
*/
|
|
943
|
-
async startPasswordless(options, storeOptions) {
|
|
971
|
+
async startPasswordless(options, storeOptions, requestOptions) {
|
|
944
972
|
const domain = await this.#resolveDomain(storeOptions);
|
|
945
973
|
const authClient = this.#getAuthClient(domain);
|
|
946
974
|
if (options.connection === "sms") {
|
|
947
|
-
await authClient.passwordless.sendSms(
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
975
|
+
await authClient.passwordless.sendSms(
|
|
976
|
+
{
|
|
977
|
+
phoneNumber: options.phoneNumber,
|
|
978
|
+
language: options.language
|
|
979
|
+
},
|
|
980
|
+
requestOptions
|
|
981
|
+
);
|
|
951
982
|
return;
|
|
952
983
|
}
|
|
953
984
|
if (options.send !== "link") {
|
|
954
|
-
await authClient.passwordless.sendEmail(
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
985
|
+
await authClient.passwordless.sendEmail(
|
|
986
|
+
{
|
|
987
|
+
email: options.email,
|
|
988
|
+
send: "code",
|
|
989
|
+
language: options.language
|
|
990
|
+
},
|
|
991
|
+
requestOptions
|
|
992
|
+
);
|
|
959
993
|
return;
|
|
960
994
|
}
|
|
961
995
|
if (!options.redirectUri || typeof options.redirectUri !== "string") {
|
|
@@ -964,19 +998,22 @@ var ServerClient = class {
|
|
|
964
998
|
const state = crypto.randomUUID();
|
|
965
999
|
const scope = ensureOpenIdScope(options.scope ?? this.#options.authorizationParams?.scope);
|
|
966
1000
|
const audience = options.audience ?? this.#options.authorizationParams?.audience;
|
|
967
|
-
await authClient.passwordless.sendEmail(
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
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
|
+
);
|
|
980
1017
|
const transactionState = {
|
|
981
1018
|
audience,
|
|
982
1019
|
domain,
|
|
@@ -984,42 +1021,42 @@ var ServerClient = class {
|
|
|
984
1021
|
};
|
|
985
1022
|
await this.#transactionStore.set(this.#transactionStoreIdentifier, transactionState, false, storeOptions);
|
|
986
1023
|
}
|
|
987
|
-
|
|
988
|
-
* Completes a passwordless OTP login and persists the resulting session.
|
|
989
|
-
*
|
|
990
|
-
* Discriminated on `connection` to mirror the `@auth0/nextjs-auth0` `passwordless.verify()`
|
|
991
|
-
* surface. Non-redirect flow: no PKCE and no transaction store (mirrors
|
|
992
|
-
* {@link ServerClient#loginBackchannel}). The `openid` scope is always ensured by this layer.
|
|
993
|
-
*
|
|
994
|
-
* Note: the state store is read-then-written; if your deployment performs concurrent
|
|
995
|
-
* logins for the same session identifier, use a state store with atomic/serializable
|
|
996
|
-
* writes to avoid last-write-wins races.
|
|
997
|
-
*
|
|
998
|
-
* @param options Discriminated completion options (`connection`, identifier, `verificationCode`).
|
|
999
|
-
* @param storeOptions Optional options passed to the resolver / stores.
|
|
1000
|
-
*
|
|
1001
|
-
* @throws {PasswordlessVerifyError} If the code is invalid, expired, or rate-limited. When the
|
|
1002
|
-
* connection requires MFA, the server responds with `mfa_required`; narrow the thrown error
|
|
1003
|
-
* with `isMfaRequiredError(error)` to read `cause.mfa_token`.
|
|
1004
|
-
*
|
|
1005
|
-
* @returns A promise resolving to the authorizationDetails (when RAR was used).
|
|
1006
|
-
*/
|
|
1007
|
-
async completePasswordless(options, storeOptions) {
|
|
1024
|
+
async completePasswordless(options, storeOptions, requestOptions) {
|
|
1008
1025
|
const scope = ensureOpenIdScope(options.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
|
|
1009
1026
|
const audience = options.authorizationParams?.audience ?? this.#options.authorizationParams?.audience;
|
|
1010
1027
|
const domain = await this.#resolveDomain(storeOptions);
|
|
1011
1028
|
const authClient = this.#getAuthClient(domain);
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
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
|
+
}
|
|
1023
1060
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
1024
1061
|
const stateData = updateStateData(
|
|
1025
1062
|
this.#options.authorizationParams?.audience ?? "default",
|
|
@@ -1028,9 +1065,16 @@ var ServerClient = class {
|
|
|
1028
1065
|
{ domain }
|
|
1029
1066
|
);
|
|
1030
1067
|
await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
|
|
1031
|
-
|
|
1068
|
+
const result = {
|
|
1032
1069
|
authorizationDetails: tokenEndpointResponse.authorizationDetails
|
|
1033
1070
|
};
|
|
1071
|
+
if (options.fullResponse) {
|
|
1072
|
+
if (!response) {
|
|
1073
|
+
throw new MissingCapturedResponseError();
|
|
1074
|
+
}
|
|
1075
|
+
return { data: result, response };
|
|
1076
|
+
}
|
|
1077
|
+
return result;
|
|
1034
1078
|
}
|
|
1035
1079
|
/**
|
|
1036
1080
|
* Completes a passwordless magic-link login and persists the resulting session.
|
|
@@ -1042,6 +1086,7 @@ var ServerClient = class {
|
|
|
1042
1086
|
*
|
|
1043
1087
|
* @param url The callback URL containing the authorization `code` and `state`.
|
|
1044
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.
|
|
1045
1090
|
*
|
|
1046
1091
|
* @throws {MissingTransactionError} If no magic-link transaction was found.
|
|
1047
1092
|
* @throws {PasswordlessVerifyError} If the returned `state` is missing or does not match.
|
|
@@ -1052,7 +1097,7 @@ var ServerClient = class {
|
|
|
1052
1097
|
* @example
|
|
1053
1098
|
* const result = await serverClient.completePasswordlessMagicLink(callbackUrl, storeOptions);
|
|
1054
1099
|
*/
|
|
1055
|
-
async completePasswordlessMagicLink(url, storeOptions) {
|
|
1100
|
+
async completePasswordlessMagicLink(url, storeOptions, requestOptions) {
|
|
1056
1101
|
const transactionData = await this.#transactionStore.get(this.#transactionStoreIdentifier, storeOptions);
|
|
1057
1102
|
if (!transactionData) {
|
|
1058
1103
|
throw new MissingTransactionError();
|
|
@@ -1064,7 +1109,7 @@ var ServerClient = class {
|
|
|
1064
1109
|
}
|
|
1065
1110
|
const domain = transactionData.domain ?? await this.#resolveDomain(storeOptions);
|
|
1066
1111
|
const authClient = this.#getAuthClient(domain);
|
|
1067
|
-
const tokenEndpointResponse = await authClient.getTokenByMagicLinkCode(url, { expectedState });
|
|
1112
|
+
const tokenEndpointResponse = await authClient.getTokenByMagicLinkCode(url, { expectedState }, requestOptions);
|
|
1068
1113
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
1069
1114
|
const stateData = updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse, {
|
|
1070
1115
|
domain
|
|
@@ -1077,6 +1122,12 @@ var ServerClient = class {
|
|
|
1077
1122
|
}
|
|
1078
1123
|
/**
|
|
1079
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
|
+
*
|
|
1080
1131
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
1081
1132
|
* @returns The user, or undefined if no user found in the store.
|
|
1082
1133
|
*/
|
|
@@ -1119,6 +1170,34 @@ var ServerClient = class {
|
|
|
1119
1170
|
return sessionData;
|
|
1120
1171
|
}
|
|
1121
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
|
+
}
|
|
1122
1201
|
/**
|
|
1123
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.
|
|
1124
1203
|
* Also updates the store when a new token was retrieved from Auth0.
|
|
@@ -1127,19 +1206,30 @@ var ServerClient = class {
|
|
|
1127
1206
|
* request an access token for that audience/scope (Multi-Resource Refresh Tokens). Tokens are cached per
|
|
1128
1207
|
* audience and scope combination.
|
|
1129
1208
|
*
|
|
1130
|
-
*
|
|
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.
|
|
1131
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.
|
|
1132
1222
|
*
|
|
1133
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`.
|
|
1134
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.
|
|
1135
1225
|
*
|
|
1136
|
-
* @returns The Token Set
|
|
1226
|
+
* @returns The Token Set when `fullResponse` is omitted, or an {@link ApiResponse} envelope when `fullResponse: true`.
|
|
1137
1227
|
*/
|
|
1138
|
-
async getAccessToken(tokenOptionsOrStoreOptions, storeOptions) {
|
|
1228
|
+
async getAccessToken(tokenOptionsOrStoreOptions, storeOptions, requestOptions) {
|
|
1139
1229
|
const hasTokenOptions = (
|
|
1140
1230
|
// If second arg exists, first arg must be GetAccessTokenOptions
|
|
1141
|
-
storeOptions !== void 0 || // OR if first arg has audience
|
|
1142
|
-
!!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)
|
|
1143
1233
|
);
|
|
1144
1234
|
const [resolvedOptions, resolvedStoreOptions] = hasTokenOptions ? [tokenOptionsOrStoreOptions, storeOptions] : [void 0, tokenOptionsOrStoreOptions];
|
|
1145
1235
|
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, resolvedStoreOptions);
|
|
@@ -1167,7 +1257,9 @@ var ServerClient = class {
|
|
|
1167
1257
|
(tokenSet2) => tokenSet2.audience === audience && (!scope || compareScopes(tokenSet2.scope, scope))
|
|
1168
1258
|
);
|
|
1169
1259
|
if (tokenSet && tokenSet.expiresAt > Date.now() / 1e3) {
|
|
1170
|
-
|
|
1260
|
+
if (!resolvedOptions?.fullResponse) {
|
|
1261
|
+
return tokenSet;
|
|
1262
|
+
}
|
|
1171
1263
|
}
|
|
1172
1264
|
if (!stateData?.refreshToken) {
|
|
1173
1265
|
throw new TokenByRefreshTokenError(
|
|
@@ -1184,35 +1276,38 @@ var ServerClient = class {
|
|
|
1184
1276
|
...scope && { scope }
|
|
1185
1277
|
}
|
|
1186
1278
|
};
|
|
1187
|
-
|
|
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
|
+
}
|
|
1188
1291
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, resolvedStoreOptions);
|
|
1189
1292
|
const updatedStateData = updateStateData(audience, existingStateData, tokenEndpointResponse, {
|
|
1190
1293
|
domain: domainForSession
|
|
1191
1294
|
});
|
|
1192
1295
|
await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, resolvedStoreOptions);
|
|
1193
|
-
|
|
1296
|
+
const returnTokenSet = {
|
|
1194
1297
|
accessToken: tokenEndpointResponse.accessToken,
|
|
1195
1298
|
scope: tokenEndpointResponse.scope,
|
|
1196
1299
|
expiresAt: tokenEndpointResponse.expiresAt,
|
|
1197
1300
|
audience
|
|
1198
1301
|
};
|
|
1302
|
+
if (resolvedOptions?.fullResponse) {
|
|
1303
|
+
if (!response) {
|
|
1304
|
+
throw new MissingCapturedResponseError();
|
|
1305
|
+
}
|
|
1306
|
+
return { data: returnTokenSet, response };
|
|
1307
|
+
}
|
|
1308
|
+
return returnTokenSet;
|
|
1199
1309
|
}
|
|
1200
|
-
|
|
1201
|
-
* Retrieves an access token for a connection.
|
|
1202
|
-
*
|
|
1203
|
-
* This method attempts to obtain an access token for a specified connection.
|
|
1204
|
-
* It first checks if a refresh token exists in the store.
|
|
1205
|
-
* If no refresh token is found, it throws an `AccessTokenForConnectionError` indicating
|
|
1206
|
-
* that the refresh token was not found.
|
|
1207
|
-
*
|
|
1208
|
-
* @param options - Options for retrieving an access token for a connection.
|
|
1209
|
-
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
1210
|
-
*
|
|
1211
|
-
* @throws {TokenForConnectionError} If the refresh token was not found or there was an issue requesting the access token.
|
|
1212
|
-
*
|
|
1213
|
-
* @returns The Connection Token Set, containing the access token for the connection, as well as additional information.
|
|
1214
|
-
*/
|
|
1215
|
-
async getAccessTokenForConnection(options, storeOptions) {
|
|
1310
|
+
async getAccessTokenForConnection(options, storeOptions, requestOptions) {
|
|
1216
1311
|
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
1217
1312
|
const sessionDomain = stateData ? this.#getSessionDomain(stateData) : this.#staticDomain;
|
|
1218
1313
|
if (this.#isResolverMode()) {
|
|
@@ -1231,7 +1326,9 @@ var ServerClient = class {
|
|
|
1231
1326
|
(tokenSet) => tokenSet.connection === options.connection
|
|
1232
1327
|
);
|
|
1233
1328
|
if (connectionTokenSet && connectionTokenSet.expiresAt > Date.now() / 1e3) {
|
|
1234
|
-
|
|
1329
|
+
if (!options.fullResponse) {
|
|
1330
|
+
return connectionTokenSet;
|
|
1331
|
+
}
|
|
1235
1332
|
}
|
|
1236
1333
|
if (!stateData?.refreshToken) {
|
|
1237
1334
|
throw new TokenForConnectionError(
|
|
@@ -1239,11 +1336,24 @@ var ServerClient = class {
|
|
|
1239
1336
|
);
|
|
1240
1337
|
}
|
|
1241
1338
|
const domainForSession = sessionDomain;
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
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
|
+
}
|
|
1247
1357
|
const updatedStateData = updateStateDataForConnectionTokenSet(
|
|
1248
1358
|
options,
|
|
1249
1359
|
{
|
|
@@ -1253,13 +1363,20 @@ var ServerClient = class {
|
|
|
1253
1363
|
tokenEndpointResponse
|
|
1254
1364
|
);
|
|
1255
1365
|
await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, storeOptions);
|
|
1256
|
-
|
|
1366
|
+
const returnConnectionTokenSet = {
|
|
1257
1367
|
accessToken: tokenEndpointResponse.accessToken,
|
|
1258
1368
|
scope: tokenEndpointResponse.scope,
|
|
1259
1369
|
expiresAt: tokenEndpointResponse.expiresAt,
|
|
1260
1370
|
connection: options.connection,
|
|
1261
1371
|
loginHint: options.loginHint
|
|
1262
1372
|
};
|
|
1373
|
+
if (options.fullResponse) {
|
|
1374
|
+
if (!response) {
|
|
1375
|
+
throw new MissingCapturedResponseError();
|
|
1376
|
+
}
|
|
1377
|
+
return { data: returnConnectionTokenSet, response };
|
|
1378
|
+
}
|
|
1379
|
+
return returnConnectionTokenSet;
|
|
1263
1380
|
}
|
|
1264
1381
|
/**
|
|
1265
1382
|
* Revokes the refresh token stored in the current session, or an explicitly supplied token.
|
|
@@ -1271,12 +1388,13 @@ var ServerClient = class {
|
|
|
1271
1388
|
*
|
|
1272
1389
|
* @param options Optionally supply a token to revoke instead of reading from the session.
|
|
1273
1390
|
* @param storeOptions Optional options passed to the StateStore.
|
|
1391
|
+
* @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the revocation request.
|
|
1274
1392
|
*
|
|
1275
1393
|
* @throws {MissingRequiredArgumentError} If `options.token` is an empty string.
|
|
1276
1394
|
* @throws {MissingSessionError} If no refresh token is found in the session and none was provided.
|
|
1277
1395
|
* @throws {TokenRevocationError} If the revocation request fails.
|
|
1278
1396
|
*/
|
|
1279
|
-
async revokeRefreshToken(options = {}, storeOptions) {
|
|
1397
|
+
async revokeRefreshToken(options = {}, storeOptions, requestOptions) {
|
|
1280
1398
|
if (options.token !== void 0 && options.token.length === 0) {
|
|
1281
1399
|
throw new MissingRequiredArgumentError("options.token must not be an empty string.");
|
|
1282
1400
|
}
|
|
@@ -1300,18 +1418,19 @@ var ServerClient = class {
|
|
|
1300
1418
|
} else {
|
|
1301
1419
|
authClient = this.authClient;
|
|
1302
1420
|
}
|
|
1303
|
-
await authClient.revokeToken({ token: refreshToken, tokenTypeHint: "refresh_token" });
|
|
1421
|
+
await authClient.revokeToken({ token: refreshToken, tokenTypeHint: "refresh_token" }, requestOptions);
|
|
1304
1422
|
}
|
|
1305
1423
|
/**
|
|
1306
1424
|
* Logs the user out and returns a URL to redirect the user-agent to after they log out.
|
|
1307
1425
|
* @param options Options used to configure the logout process.
|
|
1308
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.
|
|
1309
1428
|
* @returns {URL}
|
|
1310
1429
|
*/
|
|
1311
|
-
async logout(options, storeOptions) {
|
|
1430
|
+
async logout(options, storeOptions, requestOptions) {
|
|
1312
1431
|
if (!this.#isResolverMode()) {
|
|
1313
1432
|
try {
|
|
1314
|
-
await this.revokeRefreshToken({}, storeOptions);
|
|
1433
|
+
await this.revokeRefreshToken({}, storeOptions, requestOptions);
|
|
1315
1434
|
} catch {
|
|
1316
1435
|
}
|
|
1317
1436
|
await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
|
|
@@ -1327,39 +1446,33 @@ var ServerClient = class {
|
|
|
1327
1446
|
const domainMatches = sessionDomain === resolvedDomain;
|
|
1328
1447
|
if (domainMatches) {
|
|
1329
1448
|
try {
|
|
1330
|
-
await this.revokeRefreshToken({}, storeOptions);
|
|
1449
|
+
await this.revokeRefreshToken({}, storeOptions, requestOptions);
|
|
1331
1450
|
} catch {
|
|
1332
1451
|
}
|
|
1333
1452
|
await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
|
|
1334
1453
|
}
|
|
1335
1454
|
return authClient.buildLogoutUrl(options);
|
|
1336
1455
|
}
|
|
1337
|
-
|
|
1338
|
-
* Exchanges a custom token for Auth0 tokens and persists the resulting session (RFC 8693).
|
|
1339
|
-
*
|
|
1340
|
-
* Calls the token endpoint using the RFC 8693 Token Exchange grant, then stores the
|
|
1341
|
-
* resulting tokens in the StateStore — effectively logging the user in without an
|
|
1342
|
-
* interactive browser flow. Use this when the caller already holds a trusted external
|
|
1343
|
-
* token (e.g. a Google ID token, a legacy system token) and wants to establish an
|
|
1344
|
-
* Auth0 session from it.
|
|
1345
|
-
*
|
|
1346
|
-
* Requires a Token Exchange Profile configured in your Auth0 tenant.
|
|
1347
|
-
*
|
|
1348
|
-
* @param options Options for the custom token exchange, including the subject token and its type.
|
|
1349
|
-
* @param storeOptions Optional options passed to the StateStore.
|
|
1350
|
-
*
|
|
1351
|
-
* @throws {TokenExchangeError} If the exchange fails or the subject token is invalid.
|
|
1352
|
-
* @throws {MissingClientAuthError} If client credentials are not configured.
|
|
1353
|
-
*
|
|
1354
|
-
* @returns A promise resolving to an object containing `authorizationDetails` when RAR was used.
|
|
1355
|
-
*/
|
|
1356
|
-
async loginWithCustomTokenExchange(options, storeOptions) {
|
|
1456
|
+
async loginWithCustomTokenExchange(options, storeOptions, requestOptions) {
|
|
1357
1457
|
const domain = await this.#resolveDomain(storeOptions);
|
|
1358
1458
|
const authClient = this.#getAuthClient(domain);
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
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
|
+
}
|
|
1363
1476
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
1364
1477
|
const stateData = updateStateData(
|
|
1365
1478
|
this.#options.authorizationParams?.audience ?? "default",
|
|
@@ -1368,30 +1481,25 @@ var ServerClient = class {
|
|
|
1368
1481
|
{ domain }
|
|
1369
1482
|
);
|
|
1370
1483
|
await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
|
|
1371
|
-
|
|
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;
|
|
1372
1494
|
}
|
|
1373
|
-
|
|
1374
|
-
* Exchanges a custom token for Auth0 tokens without establishing a session (RFC 8693).
|
|
1375
|
-
*
|
|
1376
|
-
* Performs the same RFC 8693 Token Exchange as `loginWithCustomTokenExchange` but
|
|
1377
|
-
* returns the raw token response without writing anything to the StateStore. Use this
|
|
1378
|
-
* for delegation or impersonation flows where you need downstream tokens but do not
|
|
1379
|
-
* want to create or modify the current user session.
|
|
1380
|
-
*
|
|
1381
|
-
* Requires a Token Exchange Profile configured in your Auth0 tenant.
|
|
1382
|
-
*
|
|
1383
|
-
* @param options Options for the custom token exchange, including the subject token and its type.
|
|
1384
|
-
* @param storeOptions Optional options passed to the StateStore (used only for domain resolution in resolver mode).
|
|
1385
|
-
*
|
|
1386
|
-
* @throws {TokenExchangeError} If the exchange fails or the subject token is invalid.
|
|
1387
|
-
* @throws {MissingClientAuthError} If client credentials are not configured.
|
|
1388
|
-
*
|
|
1389
|
-
* @returns A promise resolving to the token response from Auth0.
|
|
1390
|
-
*/
|
|
1391
|
-
async customTokenExchange(options, storeOptions) {
|
|
1495
|
+
async customTokenExchange(options, storeOptions, requestOptions) {
|
|
1392
1496
|
const domain = await this.#resolveDomain(storeOptions);
|
|
1393
1497
|
const authClient = this.#getAuthClient(domain);
|
|
1394
|
-
|
|
1498
|
+
if (options.fullResponse) {
|
|
1499
|
+
const { fullResponse: _, ...rest } = options;
|
|
1500
|
+
return authClient.exchangeToken({ ...rest, fullResponse: true }, requestOptions);
|
|
1501
|
+
}
|
|
1502
|
+
return authClient.exchangeToken(options, requestOptions);
|
|
1395
1503
|
}
|
|
1396
1504
|
/**
|
|
1397
1505
|
* Requests a Session Transfer Token (STT) for impersonation via session transfer (RFC 8693).
|
|
@@ -1415,8 +1523,17 @@ var ServerClient = class {
|
|
|
1415
1523
|
* {@link ServerClient.buildSessionTransferRedirect}, which is forwarded to the target's
|
|
1416
1524
|
* `/authorize` on the redirect.
|
|
1417
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
|
+
*
|
|
1418
1534
|
* @param options Options including the developer-supplied `subjectToken`/`subjectTokenType` and an optional explicit `actor`.
|
|
1419
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.
|
|
1420
1537
|
*
|
|
1421
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.
|
|
1422
1539
|
* @throws {MissingClientAuthError} When client credentials are not configured (STT requires a confidential client).
|
|
@@ -1425,7 +1542,7 @@ var ServerClient = class {
|
|
|
1425
1542
|
*
|
|
1426
1543
|
* @returns A promise resolving to a {@link SessionTransferTokenResult} containing the STT and its metadata.
|
|
1427
1544
|
*/
|
|
1428
|
-
async requestSessionTransferToken(options, storeOptions) {
|
|
1545
|
+
async requestSessionTransferToken(options, storeOptions, requestOptions) {
|
|
1429
1546
|
if (!options.subjectToken || !options.subjectToken.trim()) {
|
|
1430
1547
|
throw new MissingRequiredArgumentError("subjectToken");
|
|
1431
1548
|
}
|
|
@@ -1451,7 +1568,7 @@ var ServerClient = class {
|
|
|
1451
1568
|
// `/authorize`; neither implies the other.
|
|
1452
1569
|
organization: options.organization,
|
|
1453
1570
|
extra: options.extra
|
|
1454
|
-
});
|
|
1571
|
+
}, requestOptions);
|
|
1455
1572
|
return {
|
|
1456
1573
|
sessionTransferToken: response.accessToken,
|
|
1457
1574
|
// Surface exactly what the server returned — never fabricate the URN, so a non-STT
|
|
@@ -1575,6 +1692,11 @@ var ServerClient = class {
|
|
|
1575
1692
|
}
|
|
1576
1693
|
/**
|
|
1577
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
|
+
*
|
|
1578
1700
|
* @param logoutToken The logout token to verify and use to delete the session from the store.
|
|
1579
1701
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
1580
1702
|
*
|
|
@@ -1734,7 +1856,8 @@ import {
|
|
|
1734
1856
|
OrganizationValidationError as OrganizationValidationError3,
|
|
1735
1857
|
PasswordlessStartError as PasswordlessStartError2,
|
|
1736
1858
|
PasswordlessVerifyError as PasswordlessVerifyError2,
|
|
1737
|
-
isMfaRequiredError as isMfaRequiredError2
|
|
1859
|
+
isMfaRequiredError as isMfaRequiredError2,
|
|
1860
|
+
UserInfoError
|
|
1738
1861
|
} from "@auth0/auth0-auth-js";
|
|
1739
1862
|
|
|
1740
1863
|
// src/store/cookie-transaction-store.ts
|
|
@@ -1984,6 +2107,7 @@ export {
|
|
|
1984
2107
|
TokenExchangeError2 as TokenExchangeError,
|
|
1985
2108
|
TokenExchangeErrorCode,
|
|
1986
2109
|
TokenRevocationError,
|
|
2110
|
+
UserInfoError,
|
|
1987
2111
|
isMfaRequiredError2 as isMfaRequiredError
|
|
1988
2112
|
};
|
|
1989
2113
|
//# sourceMappingURL=index.js.map
|