@auth0/auth0-server-js 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/index.cjs +384 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +143 -8
- package/dist/index.d.ts +143 -8
- package/dist/index.js +378 -53
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -41,6 +41,13 @@ var InvalidConfigurationError = class extends Error {
|
|
|
41
41
|
this.name = "InvalidConfigurationError";
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
|
+
var IssuerValidationError = class extends Error {
|
|
45
|
+
code = "issuer_validation_error";
|
|
46
|
+
constructor(message) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = "IssuerValidationError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
44
51
|
|
|
45
52
|
// src/state/utils.ts
|
|
46
53
|
var createUpdatedTokenSet = (audience, response) => ({
|
|
@@ -49,7 +56,18 @@ var createUpdatedTokenSet = (audience, response) => ({
|
|
|
49
56
|
scope: response.scope,
|
|
50
57
|
expiresAt: response.expiresAt
|
|
51
58
|
});
|
|
52
|
-
function updateStateData(audience, stateData, tokenEndpointResponse) {
|
|
59
|
+
function updateStateData(audience, stateData, tokenEndpointResponse, context) {
|
|
60
|
+
if (stateData && tokenEndpointResponse.claims) {
|
|
61
|
+
const newSub = tokenEndpointResponse.claims.sub;
|
|
62
|
+
const newIss = tokenEndpointResponse.claims.iss;
|
|
63
|
+
const existingSub = stateData.user?.sub;
|
|
64
|
+
const existingIss = stateData.user?.iss;
|
|
65
|
+
const subMismatch = newSub !== void 0 && existingSub !== void 0 && newSub !== existingSub;
|
|
66
|
+
const issMismatch = newIss !== void 0 && existingIss !== void 0 && newIss !== existingIss;
|
|
67
|
+
if (subMismatch || issMismatch) {
|
|
68
|
+
stateData = void 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
53
71
|
if (stateData) {
|
|
54
72
|
const isNewTokenSet = !stateData.tokenSets.some(
|
|
55
73
|
(tokenSet) => tokenSet.audience === audience && tokenSet.scope === tokenEndpointResponse.scope
|
|
@@ -61,7 +79,8 @@ function updateStateData(audience, stateData, tokenEndpointResponse) {
|
|
|
61
79
|
...stateData,
|
|
62
80
|
idToken: tokenEndpointResponse.idToken ?? stateData.idToken,
|
|
63
81
|
refreshToken: tokenEndpointResponse.refreshToken ?? stateData.refreshToken,
|
|
64
|
-
tokenSets
|
|
82
|
+
tokenSets,
|
|
83
|
+
domain: context?.domain ?? stateData.domain
|
|
65
84
|
};
|
|
66
85
|
} else {
|
|
67
86
|
const user = tokenEndpointResponse.claims;
|
|
@@ -69,9 +88,8 @@ function updateStateData(audience, stateData, tokenEndpointResponse) {
|
|
|
69
88
|
user,
|
|
70
89
|
idToken: tokenEndpointResponse.idToken,
|
|
71
90
|
refreshToken: tokenEndpointResponse.refreshToken,
|
|
72
|
-
tokenSets: [
|
|
73
|
-
|
|
74
|
-
],
|
|
91
|
+
tokenSets: [createUpdatedTokenSet(audience, tokenEndpointResponse)],
|
|
92
|
+
domain: context?.domain,
|
|
75
93
|
internal: {
|
|
76
94
|
sid: user?.sid,
|
|
77
95
|
createdAt: Math.floor(Date.now() / 1e3)
|
|
@@ -120,6 +138,9 @@ var compareScopes = (scopes, requiredScopes) => {
|
|
|
120
138
|
return requiredScopesArray.every((scope) => scopesSet.has(scope));
|
|
121
139
|
};
|
|
122
140
|
|
|
141
|
+
// src/server-client.ts
|
|
142
|
+
import { decodeJwt } from "jose";
|
|
143
|
+
|
|
123
144
|
// src/telemetry.ts
|
|
124
145
|
function getTelemetryConfig(config) {
|
|
125
146
|
if (config?.enabled === false) {
|
|
@@ -128,13 +149,106 @@ function getTelemetryConfig(config) {
|
|
|
128
149
|
return {
|
|
129
150
|
enabled: true,
|
|
130
151
|
name: config?.name ?? "@auth0/auth0-server-js",
|
|
131
|
-
version: config?.version ?? "1.
|
|
152
|
+
version: config?.version ?? "1.5.0"
|
|
132
153
|
};
|
|
133
154
|
}
|
|
134
155
|
|
|
156
|
+
// src/mfa/server-mfa-client.ts
|
|
157
|
+
var ServerMfaClient = class {
|
|
158
|
+
#options;
|
|
159
|
+
/**
|
|
160
|
+
* @internal
|
|
161
|
+
*/
|
|
162
|
+
constructor(options) {
|
|
163
|
+
this.#options = options;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Lists all MFA authenticators enrolled by the user.
|
|
167
|
+
*
|
|
168
|
+
* @param options - Options for listing authenticators
|
|
169
|
+
* @returns Promise resolving to an array of enrolled authenticators
|
|
170
|
+
* @throws {MfaListAuthenticatorsError} When the request fails
|
|
171
|
+
*/
|
|
172
|
+
async listAuthenticators(options) {
|
|
173
|
+
return this.#options.authClient.mfa.listAuthenticators(options);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Enrolls a new MFA authenticator for the user.
|
|
177
|
+
*
|
|
178
|
+
* @param options - Enrollment options
|
|
179
|
+
* @returns Promise resolving to enrollment response with authenticator details
|
|
180
|
+
* @throws {MfaEnrollmentError} When enrollment fails
|
|
181
|
+
*/
|
|
182
|
+
async enrollAuthenticator(options) {
|
|
183
|
+
return this.#options.authClient.mfa.enrollAuthenticator(options);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Initiates an MFA challenge for user verification.
|
|
187
|
+
*
|
|
188
|
+
* @param options - Challenge options
|
|
189
|
+
* @returns Promise resolving to challenge response with challenge details
|
|
190
|
+
* @throws {MfaChallengeError} When the challenge fails
|
|
191
|
+
*/
|
|
192
|
+
async challengeAuthenticator(options) {
|
|
193
|
+
return this.#options.authClient.mfa.challengeAuthenticator(options);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Verifies an MFA challenge and completes the authentication flow.
|
|
197
|
+
*
|
|
198
|
+
* Exchanges the MFA token and verification code for access, ID, and refresh tokens,
|
|
199
|
+
* then saves them into the user's session automatically.
|
|
200
|
+
*
|
|
201
|
+
* @param options - The MFA token, factor type (otp / oob / recovery-code), and the code to verify
|
|
202
|
+
* @param storeOptions - Optional options forwarded to the session store. Can be omitted when
|
|
203
|
+
* using the built-in stores; required if your custom store needs extra context (e.g. a request object).
|
|
204
|
+
* @returns The tokens returned by Auth0 after successful verification
|
|
205
|
+
* @throws {MfaVerifyError} When verification fails (e.g. invalid token, wrong code)
|
|
206
|
+
*/
|
|
207
|
+
async verify(options, storeOptions) {
|
|
208
|
+
const tokenResponse = await this.#options.authClient.mfa.verify(options);
|
|
209
|
+
const audience = options.audience ?? this.#options.defaultAudience;
|
|
210
|
+
const existingStateData = await this.#options.stateStore.get(
|
|
211
|
+
this.#options.stateStoreIdentifier,
|
|
212
|
+
storeOptions
|
|
213
|
+
);
|
|
214
|
+
const updatedStateData = updateStateData(audience, existingStateData, tokenResponse, {
|
|
215
|
+
domain: this.#options.domain
|
|
216
|
+
});
|
|
217
|
+
await this.#options.stateStore.set(
|
|
218
|
+
this.#options.stateStoreIdentifier,
|
|
219
|
+
updatedStateData,
|
|
220
|
+
true,
|
|
221
|
+
storeOptions
|
|
222
|
+
);
|
|
223
|
+
const result = {
|
|
224
|
+
accessToken: tokenResponse.accessToken,
|
|
225
|
+
tokenType: tokenResponse.tokenType ?? "bearer",
|
|
226
|
+
expiresAt: tokenResponse.expiresAt,
|
|
227
|
+
scope: tokenResponse.scope
|
|
228
|
+
};
|
|
229
|
+
if (tokenResponse.idToken) result.idToken = tokenResponse.idToken;
|
|
230
|
+
if (tokenResponse.refreshToken) result.refreshToken = tokenResponse.refreshToken;
|
|
231
|
+
if (tokenResponse.recoveryCode) result.recoveryCode = tokenResponse.recoveryCode;
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
135
236
|
// src/server-client.ts
|
|
136
237
|
var DEFAULT_SCOPES = "openid profile email offline_access";
|
|
137
|
-
|
|
238
|
+
var normalizeDomain = (value) => {
|
|
239
|
+
const trimmed = value.trim();
|
|
240
|
+
const parsed = trimmed.startsWith("http") ? new URL(trimmed) : new URL(`https://${trimmed}`);
|
|
241
|
+
return parsed.host.toLowerCase();
|
|
242
|
+
};
|
|
243
|
+
var decodeIssuer = (token) => {
|
|
244
|
+
try {
|
|
245
|
+
const { iss } = decodeJwt(token);
|
|
246
|
+
return typeof iss === "string" ? iss : void 0;
|
|
247
|
+
} catch {
|
|
248
|
+
return void 0;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
var ensureOpenIdScope = (scope) => {
|
|
138
252
|
if (!scope) {
|
|
139
253
|
return DEFAULT_SCOPES;
|
|
140
254
|
}
|
|
@@ -143,20 +257,51 @@ function ensureOpenIdScope(scope) {
|
|
|
143
257
|
scopes.unshift("openid");
|
|
144
258
|
}
|
|
145
259
|
return scopes.join(" ");
|
|
146
|
-
}
|
|
260
|
+
};
|
|
147
261
|
var ServerClient = class {
|
|
148
262
|
#options;
|
|
149
263
|
#transactionStore;
|
|
150
264
|
#transactionStoreIdentifier;
|
|
151
265
|
#stateStore;
|
|
152
266
|
#stateStoreIdentifier;
|
|
267
|
+
#authClientOptions;
|
|
268
|
+
#staticDomain;
|
|
269
|
+
#authClient;
|
|
270
|
+
#mfaClient;
|
|
153
271
|
/**
|
|
154
272
|
* The underlying `authClient` instance that can be used to interact with the Auth0 Authentication API.
|
|
155
273
|
* Generally, you should prefer to use the higher-level methods exposed on the `ServerClient` instance.
|
|
156
|
-
*
|
|
274
|
+
*
|
|
275
|
+
* This property can only be used when `domain` is configured as a static string.
|
|
276
|
+
* In resolver mode (`domain` as a function), the SDK resolves the domain per request,
|
|
277
|
+
* so use `ServerClient` methods instead.
|
|
278
|
+
*
|
|
157
279
|
* Important: the methods exposed on the `authClient` instance do not handle any session or state management.
|
|
158
280
|
*/
|
|
159
|
-
authClient
|
|
281
|
+
get authClient() {
|
|
282
|
+
if (!this.#authClient) {
|
|
283
|
+
throw new InvalidConfigurationError("authClient is only available when using a static domain configuration.");
|
|
284
|
+
}
|
|
285
|
+
return this.#authClient;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* The MFA client for managing multi-factor authentication operations.
|
|
289
|
+
*
|
|
290
|
+
* Provides methods to list, enroll, and challenge MFA authenticators,
|
|
291
|
+
* as well as verify MFA challenges to complete authentication.
|
|
292
|
+
*
|
|
293
|
+
* The `verify` method integrates with the session state store, persisting tokens
|
|
294
|
+
* and user data after successful MFA verification.
|
|
295
|
+
*
|
|
296
|
+
* This property can only be used when `domain` is configured as a static string.
|
|
297
|
+
* In resolver mode (`domain` as a function), MFA is not supported.
|
|
298
|
+
*/
|
|
299
|
+
get mfa() {
|
|
300
|
+
if (!this.#mfaClient) {
|
|
301
|
+
throw new InvalidConfigurationError("mfa is only available when using a static domain configuration.");
|
|
302
|
+
}
|
|
303
|
+
return this.#mfaClient;
|
|
304
|
+
}
|
|
160
305
|
constructor(options) {
|
|
161
306
|
this.#options = options;
|
|
162
307
|
this.#stateStoreIdentifier = this.#options.stateIdentifier || "__a0_session";
|
|
@@ -169,18 +314,84 @@ var ServerClient = class {
|
|
|
169
314
|
if (!this.#options.transactionStore) {
|
|
170
315
|
throw new MissingRequiredArgumentError("transactionStore");
|
|
171
316
|
}
|
|
172
|
-
this.
|
|
173
|
-
domain
|
|
317
|
+
if (typeof this.#options.domain !== "string" && typeof this.#options.domain !== "function") {
|
|
318
|
+
throw new InvalidConfigurationError("domain must be a string or resolver function");
|
|
319
|
+
}
|
|
320
|
+
this.#authClientOptions = {
|
|
174
321
|
clientId: this.#options.clientId,
|
|
175
322
|
clientSecret: this.#options.clientSecret,
|
|
176
323
|
clientAssertionSigningKey: this.#options.clientAssertionSigningKey,
|
|
177
324
|
clientAssertionSigningAlg: this.#options.clientAssertionSigningAlg,
|
|
178
325
|
authorizationParams: this.#options.authorizationParams,
|
|
326
|
+
discoveryCache: this.#options.discoveryCache,
|
|
179
327
|
customFetch: this.#options.customFetch,
|
|
180
|
-
useMtls: this.#options.useMtls
|
|
328
|
+
useMtls: this.#options.useMtls
|
|
329
|
+
};
|
|
330
|
+
if (typeof this.#options.domain === "string") {
|
|
331
|
+
const domain = normalizeDomain(this.#options.domain);
|
|
332
|
+
this.#staticDomain = domain;
|
|
333
|
+
this.#authClient = new AuthClient({
|
|
334
|
+
domain,
|
|
335
|
+
...this.#authClientOptions,
|
|
336
|
+
telemetry: getTelemetryConfig(this.#options.telemetry)
|
|
337
|
+
});
|
|
338
|
+
this.#mfaClient = new ServerMfaClient({
|
|
339
|
+
authClient: this.#authClient,
|
|
340
|
+
domain,
|
|
341
|
+
stateStore: this.#stateStore,
|
|
342
|
+
stateStoreIdentifier: this.#stateStoreIdentifier,
|
|
343
|
+
defaultAudience: this.#options.authorizationParams?.audience ?? "default"
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
async #resolveDomain(storeOptions) {
|
|
348
|
+
if (typeof this.#options.domain === "function") {
|
|
349
|
+
const resolved = await this.#options.domain(storeOptions);
|
|
350
|
+
if (typeof resolved !== "string" || resolved.trim().length === 0) {
|
|
351
|
+
throw new InvalidConfigurationError("domainResolver returned no domain");
|
|
352
|
+
}
|
|
353
|
+
return normalizeDomain(resolved);
|
|
354
|
+
}
|
|
355
|
+
return normalizeDomain(this.#options.domain);
|
|
356
|
+
}
|
|
357
|
+
#createAuthClient(domain) {
|
|
358
|
+
return new AuthClient({
|
|
359
|
+
domain,
|
|
360
|
+
...this.#authClientOptions,
|
|
181
361
|
telemetry: getTelemetryConfig(this.#options.telemetry)
|
|
182
362
|
});
|
|
183
363
|
}
|
|
364
|
+
#getAuthClient(domain) {
|
|
365
|
+
const normalizedDomain = normalizeDomain(domain);
|
|
366
|
+
if (this.#authClient && this.#staticDomain === normalizedDomain) {
|
|
367
|
+
return this.#authClient;
|
|
368
|
+
}
|
|
369
|
+
return this.#createAuthClient(normalizedDomain);
|
|
370
|
+
}
|
|
371
|
+
#getSessionDomain(stateData) {
|
|
372
|
+
if (stateData.domain) {
|
|
373
|
+
return normalizeDomain(stateData.domain);
|
|
374
|
+
}
|
|
375
|
+
if (this.#staticDomain) {
|
|
376
|
+
return this.#staticDomain;
|
|
377
|
+
}
|
|
378
|
+
const issuerFromClaims = stateData.user?.iss;
|
|
379
|
+
if (typeof issuerFromClaims === "string" && issuerFromClaims.trim().length > 0) {
|
|
380
|
+
return normalizeDomain(issuerFromClaims);
|
|
381
|
+
}
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
#isResolverMode() {
|
|
385
|
+
return typeof this.#options.domain === "function";
|
|
386
|
+
}
|
|
387
|
+
async #isSessionForCurrentDomain(stateData, storeOptions) {
|
|
388
|
+
const sessionDomain = this.#getSessionDomain(stateData);
|
|
389
|
+
if (!sessionDomain) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
const resolvedDomain = await this.#resolveDomain(storeOptions);
|
|
393
|
+
return sessionDomain === resolvedDomain;
|
|
394
|
+
}
|
|
184
395
|
/**
|
|
185
396
|
* Starts the interactive login process, and returns a URL to redirect the user-agent to to request authorization at Auth0.
|
|
186
397
|
* @param options Optional options used to configure the interactive login process.
|
|
@@ -196,7 +407,9 @@ var ServerClient = class {
|
|
|
196
407
|
throw new MissingRequiredArgumentError("authorizationParams.redirect_uri");
|
|
197
408
|
}
|
|
198
409
|
const scope = ensureOpenIdScope(options?.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
|
|
199
|
-
const
|
|
410
|
+
const domain = await this.#resolveDomain(storeOptions);
|
|
411
|
+
const authClient = this.#getAuthClient(domain);
|
|
412
|
+
const { codeVerifier, authorizationUrl } = await authClient.buildAuthorizationUrl({
|
|
200
413
|
pushedAuthorizationRequests: options?.pushedAuthorizationRequests,
|
|
201
414
|
authorizationParams: {
|
|
202
415
|
...options?.authorizationParams,
|
|
@@ -206,7 +419,8 @@ var ServerClient = class {
|
|
|
206
419
|
});
|
|
207
420
|
const transactionState = {
|
|
208
421
|
audience: options?.authorizationParams?.audience ?? this.#options.authorizationParams?.audience,
|
|
209
|
-
codeVerifier
|
|
422
|
+
codeVerifier,
|
|
423
|
+
domain
|
|
210
424
|
};
|
|
211
425
|
if (options?.appState) {
|
|
212
426
|
transactionState.appState = options.appState;
|
|
@@ -230,11 +444,15 @@ var ServerClient = class {
|
|
|
230
444
|
if (!transactionData) {
|
|
231
445
|
throw new MissingTransactionError();
|
|
232
446
|
}
|
|
233
|
-
const
|
|
447
|
+
const domain = transactionData.domain ?? await this.#resolveDomain(storeOptions);
|
|
448
|
+
const authClient = this.#getAuthClient(domain);
|
|
449
|
+
const tokenEndpointResponse = await authClient.getTokenByCode(url, {
|
|
234
450
|
codeVerifier: transactionData.codeVerifier
|
|
235
451
|
});
|
|
236
452
|
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
237
|
-
const stateData = updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse
|
|
453
|
+
const stateData = updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse, {
|
|
454
|
+
domain
|
|
455
|
+
});
|
|
238
456
|
await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
|
|
239
457
|
await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
|
|
240
458
|
return { appState: transactionData.appState, authorizationDetails: tokenEndpointResponse.authorizationDetails };
|
|
@@ -256,7 +474,15 @@ var ServerClient = class {
|
|
|
256
474
|
"Unable to start the user linking process without a logged in user. Ensure to login using the SDK before starting the user linking process."
|
|
257
475
|
);
|
|
258
476
|
}
|
|
259
|
-
|
|
477
|
+
if (this.#isResolverMode()) {
|
|
478
|
+
const isCurrentDomain = await this.#isSessionForCurrentDomain(stateData, storeOptions);
|
|
479
|
+
if (!isCurrentDomain) {
|
|
480
|
+
throw new MissingSessionError("Session domain does not match the current domain.");
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const domain = this.#getSessionDomain(stateData);
|
|
484
|
+
const authClient = this.#getAuthClient(domain);
|
|
485
|
+
const { linkUserUrl, codeVerifier } = await authClient.buildLinkUserUrl({
|
|
260
486
|
connection: options.connection,
|
|
261
487
|
connectionScope: options.connectionScope,
|
|
262
488
|
idToken: stateData.idToken,
|
|
@@ -264,7 +490,8 @@ var ServerClient = class {
|
|
|
264
490
|
});
|
|
265
491
|
const transactionState = {
|
|
266
492
|
audience: options?.authorizationParams?.audience ?? this.#options.authorizationParams?.audience,
|
|
267
|
-
codeVerifier
|
|
493
|
+
codeVerifier,
|
|
494
|
+
domain
|
|
268
495
|
};
|
|
269
496
|
if (options?.appState) {
|
|
270
497
|
transactionState.appState = options.appState;
|
|
@@ -306,14 +533,23 @@ var ServerClient = class {
|
|
|
306
533
|
"Unable to start the user unlinking process without a logged in user. Ensure to login using the SDK before starting the user unlinking process."
|
|
307
534
|
);
|
|
308
535
|
}
|
|
309
|
-
|
|
536
|
+
if (this.#isResolverMode()) {
|
|
537
|
+
const isCurrentDomain = await this.#isSessionForCurrentDomain(stateData, storeOptions);
|
|
538
|
+
if (!isCurrentDomain) {
|
|
539
|
+
throw new MissingSessionError("Session domain does not match the current domain.");
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
const domain = this.#getSessionDomain(stateData);
|
|
543
|
+
const authClient = this.#getAuthClient(domain);
|
|
544
|
+
const { unlinkUserUrl, codeVerifier } = await authClient.buildUnlinkUserUrl({
|
|
310
545
|
connection: options.connection,
|
|
311
546
|
idToken: stateData.idToken,
|
|
312
547
|
authorizationParams: options.authorizationParams
|
|
313
548
|
});
|
|
314
549
|
const transactionState = {
|
|
315
550
|
audience: options?.authorizationParams?.audience ?? this.#options.authorizationParams?.audience,
|
|
316
|
-
codeVerifier
|
|
551
|
+
codeVerifier,
|
|
552
|
+
domain
|
|
317
553
|
};
|
|
318
554
|
if (options?.appState) {
|
|
319
555
|
transactionState.appState = options.appState;
|
|
@@ -352,7 +588,9 @@ var ServerClient = class {
|
|
|
352
588
|
*/
|
|
353
589
|
async loginBackchannel(options, storeOptions) {
|
|
354
590
|
const scope = ensureOpenIdScope(options.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
|
|
355
|
-
const
|
|
591
|
+
const domain = await this.#resolveDomain(storeOptions);
|
|
592
|
+
const authClient = this.#getAuthClient(domain);
|
|
593
|
+
const tokenEndpointResponse = await authClient.backchannelAuthentication({
|
|
356
594
|
bindingMessage: options.bindingMessage,
|
|
357
595
|
loginHint: options.loginHint,
|
|
358
596
|
authorizationParams: {
|
|
@@ -364,7 +602,8 @@ var ServerClient = class {
|
|
|
364
602
|
const stateData = updateStateData(
|
|
365
603
|
this.#options.authorizationParams?.audience ?? "default",
|
|
366
604
|
existingStateData,
|
|
367
|
-
tokenEndpointResponse
|
|
605
|
+
tokenEndpointResponse,
|
|
606
|
+
{ domain }
|
|
368
607
|
);
|
|
369
608
|
await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
|
|
370
609
|
return {
|
|
@@ -378,16 +617,31 @@ var ServerClient = class {
|
|
|
378
617
|
*/
|
|
379
618
|
async getUser(storeOptions) {
|
|
380
619
|
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
381
|
-
|
|
620
|
+
if (!stateData) {
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
if (this.#isResolverMode()) {
|
|
624
|
+
const isCurrentDomain = await this.#isSessionForCurrentDomain(stateData, storeOptions);
|
|
625
|
+
if (!isCurrentDomain) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return stateData.user;
|
|
382
630
|
}
|
|
383
631
|
/**
|
|
384
632
|
* Retrieve the user session from the store, or undefined if no session found.
|
|
385
633
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
386
|
-
* @returns The
|
|
634
|
+
* @returns The session or undefined if no session found in the store.
|
|
387
635
|
*/
|
|
388
636
|
async getSession(storeOptions) {
|
|
389
637
|
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
390
638
|
if (stateData) {
|
|
639
|
+
if (this.#isResolverMode()) {
|
|
640
|
+
const isCurrentDomain = await this.#isSessionForCurrentDomain(stateData, storeOptions);
|
|
641
|
+
if (!isCurrentDomain) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
391
645
|
const { internal, ...sessionData } = stateData;
|
|
392
646
|
return sessionData;
|
|
393
647
|
}
|
|
@@ -395,24 +649,29 @@ var ServerClient = class {
|
|
|
395
649
|
/**
|
|
396
650
|
* 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.
|
|
397
651
|
* Also updates the store when a new token was retrieved from Auth0.
|
|
398
|
-
*
|
|
399
|
-
* @param options Optional options for requesting specific audience/scope.
|
|
400
652
|
* @param storeOptions Optional options used to pass to the Transaction and State Store.
|
|
401
653
|
*
|
|
402
|
-
* @throws {TokenByRefreshTokenError} If the refresh token was not found or there was an issue requesting the access token.
|
|
654
|
+
* @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`.
|
|
403
655
|
*
|
|
404
656
|
* @returns The Token Set, containing the access token, as well as additional information.
|
|
405
657
|
*/
|
|
406
|
-
async getAccessToken(
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
)
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
658
|
+
async getAccessToken(storeOptions) {
|
|
659
|
+
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
660
|
+
const audience = this.#options.authorizationParams?.audience ?? "default";
|
|
661
|
+
const scope = this.#options.authorizationParams?.scope;
|
|
662
|
+
const sessionDomain = stateData ? this.#getSessionDomain(stateData) : this.#staticDomain;
|
|
663
|
+
if (this.#isResolverMode()) {
|
|
664
|
+
if (!stateData) {
|
|
665
|
+
throw new MissingSessionError("Unable to retrieve access token without a logged in user.");
|
|
666
|
+
}
|
|
667
|
+
if (!sessionDomain) {
|
|
668
|
+
throw new MissingSessionError("Session domain does not match the current domain.");
|
|
669
|
+
}
|
|
670
|
+
const resolvedDomain = await this.#resolveDomain(storeOptions);
|
|
671
|
+
if (sessionDomain !== resolvedDomain) {
|
|
672
|
+
throw new MissingSessionError("Session domain does not match the current domain.");
|
|
673
|
+
}
|
|
674
|
+
}
|
|
416
675
|
const tokenSet = stateData?.tokenSets.find(
|
|
417
676
|
(tokenSet2) => tokenSet2.audience === audience && (!scope || compareScopes(tokenSet2.scope, scope))
|
|
418
677
|
);
|
|
@@ -424,14 +683,15 @@ var ServerClient = class {
|
|
|
424
683
|
"The access token has expired and a refresh token was not provided. The user needs to re-authenticate."
|
|
425
684
|
);
|
|
426
685
|
}
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
};
|
|
431
|
-
const
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
686
|
+
const domainForSession = sessionDomain;
|
|
687
|
+
const tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenByRefreshToken({
|
|
688
|
+
refreshToken: stateData.refreshToken
|
|
689
|
+
});
|
|
690
|
+
const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
691
|
+
const updatedStateData = updateStateData(audience, existingStateData, tokenEndpointResponse, {
|
|
692
|
+
domain: domainForSession
|
|
693
|
+
});
|
|
694
|
+
await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, storeOptions);
|
|
435
695
|
return {
|
|
436
696
|
accessToken: tokenEndpointResponse.accessToken,
|
|
437
697
|
scope: tokenEndpointResponse.scope,
|
|
@@ -456,6 +716,19 @@ var ServerClient = class {
|
|
|
456
716
|
*/
|
|
457
717
|
async getAccessTokenForConnection(options, storeOptions) {
|
|
458
718
|
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
719
|
+
const sessionDomain = stateData ? this.#getSessionDomain(stateData) : this.#staticDomain;
|
|
720
|
+
if (this.#isResolverMode()) {
|
|
721
|
+
if (!stateData) {
|
|
722
|
+
throw new MissingSessionError("Unable to retrieve an access token for a connection without a logged in user.");
|
|
723
|
+
}
|
|
724
|
+
if (!sessionDomain) {
|
|
725
|
+
throw new MissingSessionError("Session domain does not match the current domain.");
|
|
726
|
+
}
|
|
727
|
+
const resolvedDomain = await this.#resolveDomain(storeOptions);
|
|
728
|
+
if (sessionDomain !== resolvedDomain) {
|
|
729
|
+
throw new MissingSessionError("Session domain does not match the current domain.");
|
|
730
|
+
}
|
|
731
|
+
}
|
|
459
732
|
const connectionTokenSet = stateData?.connectionTokenSets?.find(
|
|
460
733
|
(tokenSet) => tokenSet.connection === options.connection
|
|
461
734
|
);
|
|
@@ -467,12 +740,20 @@ var ServerClient = class {
|
|
|
467
740
|
"A refresh token was not found but is required to be able to retrieve an access token for a connection."
|
|
468
741
|
);
|
|
469
742
|
}
|
|
470
|
-
const
|
|
743
|
+
const domainForSession = sessionDomain;
|
|
744
|
+
const tokenEndpointResponse = await this.#getAuthClient(domainForSession).getTokenForConnection({
|
|
471
745
|
connection: options.connection,
|
|
472
746
|
loginHint: options.loginHint,
|
|
473
747
|
refreshToken: stateData.refreshToken
|
|
474
748
|
});
|
|
475
|
-
const updatedStateData = updateStateDataForConnectionTokenSet(
|
|
749
|
+
const updatedStateData = updateStateDataForConnectionTokenSet(
|
|
750
|
+
options,
|
|
751
|
+
{
|
|
752
|
+
...stateData,
|
|
753
|
+
domain: stateData.domain ?? domainForSession
|
|
754
|
+
},
|
|
755
|
+
tokenEndpointResponse
|
|
756
|
+
);
|
|
476
757
|
await this.#stateStore.set(this.#stateStoreIdentifier, updatedStateData, false, storeOptions);
|
|
477
758
|
return {
|
|
478
759
|
accessToken: tokenEndpointResponse.accessToken,
|
|
@@ -489,8 +770,21 @@ var ServerClient = class {
|
|
|
489
770
|
* @returns {URL}
|
|
490
771
|
*/
|
|
491
772
|
async logout(options, storeOptions) {
|
|
492
|
-
|
|
493
|
-
|
|
773
|
+
if (!this.#isResolverMode()) {
|
|
774
|
+
await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
|
|
775
|
+
return this.authClient.buildLogoutUrl(options);
|
|
776
|
+
}
|
|
777
|
+
const resolvedDomain = await this.#resolveDomain(storeOptions);
|
|
778
|
+
const authClient = this.#getAuthClient(resolvedDomain);
|
|
779
|
+
const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
|
|
780
|
+
const sessionDomain = stateData ? this.#getSessionDomain(stateData) : void 0;
|
|
781
|
+
if (!stateData) {
|
|
782
|
+
return authClient.buildLogoutUrl(options);
|
|
783
|
+
}
|
|
784
|
+
if (sessionDomain && sessionDomain === resolvedDomain) {
|
|
785
|
+
await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
|
|
786
|
+
}
|
|
787
|
+
return authClient.buildLogoutUrl(options);
|
|
494
788
|
}
|
|
495
789
|
/**
|
|
496
790
|
* Handles the backchannel logout process by verifying the logout token and deleting the session from the store if the logout token was considered valid.
|
|
@@ -504,8 +798,23 @@ var ServerClient = class {
|
|
|
504
798
|
if (!logoutToken) {
|
|
505
799
|
throw new BackchannelLogoutError("Missing Logout Token");
|
|
506
800
|
}
|
|
507
|
-
|
|
508
|
-
|
|
801
|
+
if (!this.#isResolverMode()) {
|
|
802
|
+
const logoutTokenClaims2 = await this.authClient.verifyLogoutToken({ logoutToken });
|
|
803
|
+
await this.#stateStore.deleteByLogoutToken(logoutTokenClaims2, storeOptions);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
const issuer = decodeIssuer(logoutToken);
|
|
807
|
+
if (!issuer) {
|
|
808
|
+
throw new BackchannelLogoutError("Logout token is missing an issuer");
|
|
809
|
+
}
|
|
810
|
+
const resolvedDomain = await this.#resolveDomain(storeOptions);
|
|
811
|
+
const domain = normalizeDomain(issuer);
|
|
812
|
+
if (domain !== resolvedDomain) {
|
|
813
|
+
throw new BackchannelLogoutError("Logout token issuer does not match the resolved domain");
|
|
814
|
+
}
|
|
815
|
+
const authClient = this.#getAuthClient(domain);
|
|
816
|
+
const logoutTokenClaims = await authClient.verifyLogoutToken({ logoutToken });
|
|
817
|
+
await this.#stateStore.deleteByLogoutToken({ ...logoutTokenClaims, iss: issuer }, storeOptions);
|
|
509
818
|
}
|
|
510
819
|
};
|
|
511
820
|
|
|
@@ -823,18 +1132,34 @@ var StatelessStateStore = class extends AbstractSessionStore {
|
|
|
823
1132
|
};
|
|
824
1133
|
}
|
|
825
1134
|
};
|
|
1135
|
+
|
|
1136
|
+
// src/mfa/index.ts
|
|
1137
|
+
import {
|
|
1138
|
+
MfaListAuthenticatorsError,
|
|
1139
|
+
MfaEnrollmentError,
|
|
1140
|
+
MfaChallengeError,
|
|
1141
|
+
MfaVerifyError,
|
|
1142
|
+
isMfaRequiredError
|
|
1143
|
+
} from "@auth0/auth0-auth-js";
|
|
826
1144
|
export {
|
|
827
1145
|
AbstractStateStore,
|
|
828
1146
|
AbstractTransactionStore,
|
|
829
1147
|
BackchannelLogoutError,
|
|
830
1148
|
CookieTransactionStore,
|
|
831
1149
|
InvalidConfigurationError,
|
|
1150
|
+
IssuerValidationError,
|
|
1151
|
+
MfaChallengeError,
|
|
1152
|
+
MfaEnrollmentError,
|
|
1153
|
+
MfaListAuthenticatorsError,
|
|
1154
|
+
MfaVerifyError,
|
|
832
1155
|
MissingRequiredArgumentError,
|
|
833
1156
|
MissingSessionError,
|
|
834
1157
|
MissingTransactionError,
|
|
835
1158
|
ServerClient,
|
|
1159
|
+
ServerMfaClient,
|
|
836
1160
|
StartLinkUserError,
|
|
837
1161
|
StatefulStateStore,
|
|
838
|
-
StatelessStateStore
|
|
1162
|
+
StatelessStateStore,
|
|
1163
|
+
isMfaRequiredError
|
|
839
1164
|
};
|
|
840
1165
|
//# sourceMappingURL=index.js.map
|