UNPKG

47.2 kBJavaScriptView Raw
1/*! firebase-admin v12.0.0 */
2"use strict";
3/*!
4 * Copyright 2021 Google Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18Object.defineProperty(exports, "__esModule", { value: true });
19exports.BaseAuth = exports.createFirebaseTokenGenerator = void 0;
20const error_1 = require("../utils/error");
21const deep_copy_1 = require("../utils/deep-copy");
22const validator = require("../utils/validator");
23const auth_api_request_1 = require("./auth-api-request");
24const token_generator_1 = require("./token-generator");
25const token_verifier_1 = require("./token-verifier");
26const auth_config_1 = require("./auth-config");
27const user_record_1 = require("./user-record");
28const identifier_1 = require("./identifier");
29const crypto_signer_1 = require("../utils/crypto-signer");
30/**
31 * @internal
32 */
33function createFirebaseTokenGenerator(app, tenantId) {
34 try {
35 const signer = (0, auth_api_request_1.useEmulator)() ? new token_generator_1.EmulatedSigner() : (0, crypto_signer_1.cryptoSignerFromApp)(app);
36 return new token_generator_1.FirebaseTokenGenerator(signer, tenantId);
37 }
38 catch (err) {
39 throw (0, token_generator_1.handleCryptoSignerError)(err);
40 }
41}
42exports.createFirebaseTokenGenerator = createFirebaseTokenGenerator;
43/**
44 * Common parent interface for both `Auth` and `TenantAwareAuth` APIs.
45 */
46class BaseAuth {
47 /**
48 * The BaseAuth class constructor.
49 *
50 * @param app - The FirebaseApp to associate with this Auth instance.
51 * @param authRequestHandler - The RPC request handler for this instance.
52 * @param tokenGenerator - Optional token generator. If not specified, a
53 * (non-tenant-aware) instance will be created. Use this paramter to
54 * specify a tenant-aware tokenGenerator.
55 * @constructor
56 * @internal
57 */
58 constructor(app,
59 /** @internal */ authRequestHandler, tokenGenerator) {
60 this.authRequestHandler = authRequestHandler;
61 if (tokenGenerator) {
62 this.tokenGenerator = tokenGenerator;
63 }
64 else {
65 this.tokenGenerator = createFirebaseTokenGenerator(app);
66 }
67 this.sessionCookieVerifier = (0, token_verifier_1.createSessionCookieVerifier)(app);
68 this.idTokenVerifier = (0, token_verifier_1.createIdTokenVerifier)(app);
69 this.authBlockingTokenVerifier = (0, token_verifier_1.createAuthBlockingTokenVerifier)(app);
70 }
71 /**
72 * Creates a new Firebase custom token (JWT) that can be sent back to a client
73 * device to use to sign in with the client SDKs' `signInWithCustomToken()`
74 * methods. (Tenant-aware instances will also embed the tenant ID in the
75 * token.)
76 *
77 * See {@link https://firebase.google.com/docs/auth/admin/create-custom-tokens | Create Custom Tokens}
78 * for code samples and detailed documentation.
79 *
80 * @param uid - The `uid` to use as the custom token's subject.
81 * @param developerClaims - Optional additional claims to include
82 * in the custom token's payload.
83 *
84 * @returns A promise fulfilled with a custom token for the
85 * provided `uid` and payload.
86 */
87 createCustomToken(uid, developerClaims) {
88 return this.tokenGenerator.createCustomToken(uid, developerClaims);
89 }
90 /**
91 * Verifies a Firebase ID token (JWT). If the token is valid, the promise is
92 * fulfilled with the token's decoded claims; otherwise, the promise is
93 * rejected.
94 *
95 * If `checkRevoked` is set to true, first verifies whether the corresponding
96 * user is disabled. If yes, an `auth/user-disabled` error is thrown. If no,
97 * verifies if the session corresponding to the ID token was revoked. If the
98 * corresponding user's session was invalidated, an `auth/id-token-revoked`
99 * error is thrown. If not specified the check is not applied.
100 *
101 * See {@link https://firebase.google.com/docs/auth/admin/verify-id-tokens | Verify ID Tokens}
102 * for code samples and detailed documentation.
103 *
104 * @param idToken - The ID token to verify.
105 * @param checkRevoked - Whether to check if the ID token was revoked.
106 * This requires an extra request to the Firebase Auth backend to check
107 * the `tokensValidAfterTime` time for the corresponding user.
108 * When not specified, this additional check is not applied.
109 *
110 * @returns A promise fulfilled with the
111 * token's decoded claims if the ID token is valid; otherwise, a rejected
112 * promise.
113 */
114 verifyIdToken(idToken, checkRevoked = false) {
115 const isEmulator = (0, auth_api_request_1.useEmulator)();
116 return this.idTokenVerifier.verifyJWT(idToken, isEmulator)
117 .then((decodedIdToken) => {
118 // Whether to check if the token was revoked.
119 if (checkRevoked || isEmulator) {
120 return this.verifyDecodedJWTNotRevokedOrDisabled(decodedIdToken, error_1.AuthClientErrorCode.ID_TOKEN_REVOKED);
121 }
122 return decodedIdToken;
123 });
124 }
125 /**
126 * Gets the user data for the user corresponding to a given `uid`.
127 *
128 * See {@link https://firebase.google.com/docs/auth/admin/manage-users#retrieve_user_data | Retrieve user data}
129 * for code samples and detailed documentation.
130 *
131 * @param uid - The `uid` corresponding to the user whose data to fetch.
132 *
133 * @returns A promise fulfilled with the user
134 * data corresponding to the provided `uid`.
135 */
136 getUser(uid) {
137 return this.authRequestHandler.getAccountInfoByUid(uid)
138 .then((response) => {
139 // Returns the user record populated with server response.
140 return new user_record_1.UserRecord(response.users[0]);
141 });
142 }
143 /**
144 * Gets the user data for the user corresponding to a given email.
145 *
146 * See {@link https://firebase.google.com/docs/auth/admin/manage-users#retrieve_user_data | Retrieve user data}
147 * for code samples and detailed documentation.
148 *
149 * @param email - The email corresponding to the user whose data to
150 * fetch.
151 *
152 * @returns A promise fulfilled with the user
153 * data corresponding to the provided email.
154 */
155 getUserByEmail(email) {
156 return this.authRequestHandler.getAccountInfoByEmail(email)
157 .then((response) => {
158 // Returns the user record populated with server response.
159 return new user_record_1.UserRecord(response.users[0]);
160 });
161 }
162 /**
163 * Gets the user data for the user corresponding to a given phone number. The
164 * phone number has to conform to the E.164 specification.
165 *
166 * See {@link https://firebase.google.com/docs/auth/admin/manage-users#retrieve_user_data | Retrieve user data}
167 * for code samples and detailed documentation.
168 *
169 * @param phoneNumber - The phone number corresponding to the user whose
170 * data to fetch.
171 *
172 * @returns A promise fulfilled with the user
173 * data corresponding to the provided phone number.
174 */
175 getUserByPhoneNumber(phoneNumber) {
176 return this.authRequestHandler.getAccountInfoByPhoneNumber(phoneNumber)
177 .then((response) => {
178 // Returns the user record populated with server response.
179 return new user_record_1.UserRecord(response.users[0]);
180 });
181 }
182 /**
183 * Gets the user data for the user corresponding to a given provider id.
184 *
185 * See {@link https://firebase.google.com/docs/auth/admin/manage-users#retrieve_user_data | Retrieve user data}
186 * for code samples and detailed documentation.
187 *
188 * @param providerId - The provider ID, for example, "google.com" for the
189 * Google provider.
190 * @param uid - The user identifier for the given provider.
191 *
192 * @returns A promise fulfilled with the user data corresponding to the
193 * given provider id.
194 */
195 getUserByProviderUid(providerId, uid) {
196 // Although we don't really advertise it, we want to also handle
197 // non-federated idps with this call. So if we detect one of them, we'll
198 // reroute this request appropriately.
199 if (providerId === 'phone') {
200 return this.getUserByPhoneNumber(uid);
201 }
202 else if (providerId === 'email') {
203 return this.getUserByEmail(uid);
204 }
205 return this.authRequestHandler.getAccountInfoByFederatedUid(providerId, uid)
206 .then((response) => {
207 // Returns the user record populated with server response.
208 return new user_record_1.UserRecord(response.users[0]);
209 });
210 }
211 /**
212 * Gets the user data corresponding to the specified identifiers.
213 *
214 * There are no ordering guarantees; in particular, the nth entry in the result list is not
215 * guaranteed to correspond to the nth entry in the input parameters list.
216 *
217 * Only a maximum of 100 identifiers may be supplied. If more than 100 identifiers are supplied,
218 * this method throws a FirebaseAuthError.
219 *
220 * @param identifiers - The identifiers used to indicate which user records should be returned.
221 * Must not have more than 100 entries.
222 * @returns A promise that resolves to the corresponding user records.
223 * @throws FirebaseAuthError If any of the identifiers are invalid or if more than 100
224 * identifiers are specified.
225 */
226 getUsers(identifiers) {
227 if (!validator.isArray(identifiers)) {
228 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '`identifiers` parameter must be an array');
229 }
230 return this.authRequestHandler
231 .getAccountInfoByIdentifiers(identifiers)
232 .then((response) => {
233 /**
234 * Checks if the specified identifier is within the list of
235 * UserRecords.
236 */
237 const isUserFound = ((id, userRecords) => {
238 return !!userRecords.find((userRecord) => {
239 if ((0, identifier_1.isUidIdentifier)(id)) {
240 return id.uid === userRecord.uid;
241 }
242 else if ((0, identifier_1.isEmailIdentifier)(id)) {
243 return id.email === userRecord.email;
244 }
245 else if ((0, identifier_1.isPhoneIdentifier)(id)) {
246 return id.phoneNumber === userRecord.phoneNumber;
247 }
248 else if ((0, identifier_1.isProviderIdentifier)(id)) {
249 const matchingUserInfo = userRecord.providerData.find((userInfo) => {
250 return id.providerId === userInfo.providerId;
251 });
252 return !!matchingUserInfo && id.providerUid === matchingUserInfo.uid;
253 }
254 else {
255 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'Unhandled identifier type');
256 }
257 });
258 });
259 const users = response.users ? response.users.map((user) => new user_record_1.UserRecord(user)) : [];
260 const notFound = identifiers.filter((id) => !isUserFound(id, users));
261 return { users, notFound };
262 });
263 }
264 /**
265 * Retrieves a list of users (single batch only) with a size of `maxResults`
266 * starting from the offset as specified by `pageToken`. This is used to
267 * retrieve all the users of a specified project in batches.
268 *
269 * See {@link https://firebase.google.com/docs/auth/admin/manage-users#list_all_users | List all users}
270 * for code samples and detailed documentation.
271 *
272 * @param maxResults - The page size, 1000 if undefined. This is also
273 * the maximum allowed limit.
274 * @param pageToken - The next page token. If not specified, returns
275 * users starting without any offset.
276 * @returns A promise that resolves with
277 * the current batch of downloaded users and the next page token.
278 */
279 listUsers(maxResults, pageToken) {
280 return this.authRequestHandler.downloadAccount(maxResults, pageToken)
281 .then((response) => {
282 // List of users to return.
283 const users = [];
284 // Convert each user response to a UserRecord.
285 response.users.forEach((userResponse) => {
286 users.push(new user_record_1.UserRecord(userResponse));
287 });
288 // Return list of user records and the next page token if available.
289 const result = {
290 users,
291 pageToken: response.nextPageToken,
292 };
293 // Delete result.pageToken if undefined.
294 if (typeof result.pageToken === 'undefined') {
295 delete result.pageToken;
296 }
297 return result;
298 });
299 }
300 /**
301 * Creates a new user.
302 *
303 * See {@link https://firebase.google.com/docs/auth/admin/manage-users#create_a_user | Create a user}
304 * for code samples and detailed documentation.
305 *
306 * @param properties - The properties to set on the
307 * new user record to be created.
308 *
309 * @returns A promise fulfilled with the user
310 * data corresponding to the newly created user.
311 */
312 createUser(properties) {
313 return this.authRequestHandler.createNewAccount(properties)
314 .then((uid) => {
315 // Return the corresponding user record.
316 return this.getUser(uid);
317 })
318 .catch((error) => {
319 if (error.code === 'auth/user-not-found') {
320 // Something must have happened after creating the user and then retrieving it.
321 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'Unable to create the user record provided.');
322 }
323 throw error;
324 });
325 }
326 /**
327 * Deletes an existing user.
328 *
329 * See {@link https://firebase.google.com/docs/auth/admin/manage-users#delete_a_user | Delete a user}
330 * for code samples and detailed documentation.
331 *
332 * @param uid - The `uid` corresponding to the user to delete.
333 *
334 * @returns An empty promise fulfilled once the user has been
335 * deleted.
336 */
337 deleteUser(uid) {
338 return this.authRequestHandler.deleteAccount(uid)
339 .then(() => {
340 // Return nothing on success.
341 });
342 }
343 /**
344 * Deletes the users specified by the given uids.
345 *
346 * Deleting a non-existing user won't generate an error (i.e. this method
347 * is idempotent.) Non-existing users are considered to be successfully
348 * deleted, and are therefore counted in the
349 * `DeleteUsersResult.successCount` value.
350 *
351 * Only a maximum of 1000 identifiers may be supplied. If more than 1000
352 * identifiers are supplied, this method throws a FirebaseAuthError.
353 *
354 * This API is currently rate limited at the server to 1 QPS. If you exceed
355 * this, you may get a quota exceeded error. Therefore, if you want to
356 * delete more than 1000 users, you may need to add a delay to ensure you
357 * don't go over this limit.
358 *
359 * @param uids - The `uids` corresponding to the users to delete.
360 *
361 * @returns A Promise that resolves to the total number of successful/failed
362 * deletions, as well as the array of errors that corresponds to the
363 * failed deletions.
364 */
365 deleteUsers(uids) {
366 if (!validator.isArray(uids)) {
367 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '`uids` parameter must be an array');
368 }
369 return this.authRequestHandler.deleteAccounts(uids, /*force=*/ true)
370 .then((batchDeleteAccountsResponse) => {
371 const result = {
372 failureCount: 0,
373 successCount: uids.length,
374 errors: [],
375 };
376 if (!validator.isNonEmptyArray(batchDeleteAccountsResponse.errors)) {
377 return result;
378 }
379 result.failureCount = batchDeleteAccountsResponse.errors.length;
380 result.successCount = uids.length - batchDeleteAccountsResponse.errors.length;
381 result.errors = batchDeleteAccountsResponse.errors.map((batchDeleteErrorInfo) => {
382 if (batchDeleteErrorInfo.index === undefined) {
383 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'Corrupt BatchDeleteAccountsResponse detected');
384 }
385 const errMsgToError = (msg) => {
386 // We unconditionally set force=true, so the 'NOT_DISABLED' error
387 // should not be possible.
388 const code = msg && msg.startsWith('NOT_DISABLED') ?
389 error_1.AuthClientErrorCode.USER_NOT_DISABLED : error_1.AuthClientErrorCode.INTERNAL_ERROR;
390 return new error_1.FirebaseAuthError(code, batchDeleteErrorInfo.message);
391 };
392 return {
393 index: batchDeleteErrorInfo.index,
394 error: errMsgToError(batchDeleteErrorInfo.message),
395 };
396 });
397 return result;
398 });
399 }
400 /**
401 * Updates an existing user.
402 *
403 * See {@link https://firebase.google.com/docs/auth/admin/manage-users#update_a_user | Update a user}
404 * for code samples and detailed documentation.
405 *
406 * @param uid - The `uid` corresponding to the user to update.
407 * @param properties - The properties to update on
408 * the provided user.
409 *
410 * @returns A promise fulfilled with the
411 * updated user data.
412 */
413 updateUser(uid, properties) {
414 // Although we don't really advertise it, we want to also handle linking of
415 // non-federated idps with this call. So if we detect one of them, we'll
416 // adjust the properties parameter appropriately. This *does* imply that a
417 // conflict could arise, e.g. if the user provides a phoneNumber property,
418 // but also provides a providerToLink with a 'phone' provider id. In that
419 // case, we'll throw an error.
420 properties = (0, deep_copy_1.deepCopy)(properties);
421 if (properties?.providerToLink) {
422 if (properties.providerToLink.providerId === 'email') {
423 if (typeof properties.email !== 'undefined') {
424 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, "Both UpdateRequest.email and UpdateRequest.providerToLink.providerId='email' were set. To "
425 + 'link to the email/password provider, only specify the UpdateRequest.email field.');
426 }
427 properties.email = properties.providerToLink.uid;
428 delete properties.providerToLink;
429 }
430 else if (properties.providerToLink.providerId === 'phone') {
431 if (typeof properties.phoneNumber !== 'undefined') {
432 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, "Both UpdateRequest.phoneNumber and UpdateRequest.providerToLink.providerId='phone' were set. To "
433 + 'link to a phone provider, only specify the UpdateRequest.phoneNumber field.');
434 }
435 properties.phoneNumber = properties.providerToLink.uid;
436 delete properties.providerToLink;
437 }
438 }
439 if (properties?.providersToUnlink) {
440 if (properties.providersToUnlink.indexOf('phone') !== -1) {
441 // If we've been told to unlink the phone provider both via setting
442 // phoneNumber to null *and* by setting providersToUnlink to include
443 // 'phone', then we'll reject that. Though it might also be reasonable
444 // to relax this restriction and just unlink it.
445 if (properties.phoneNumber === null) {
446 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, "Both UpdateRequest.phoneNumber=null and UpdateRequest.providersToUnlink=['phone'] were set. To "
447 + 'unlink from a phone provider, only specify the UpdateRequest.phoneNumber=null field.');
448 }
449 }
450 }
451 return this.authRequestHandler.updateExistingAccount(uid, properties)
452 .then((existingUid) => {
453 // Return the corresponding user record.
454 return this.getUser(existingUid);
455 });
456 }
457 /**
458 * Sets additional developer claims on an existing user identified by the
459 * provided `uid`, typically used to define user roles and levels of
460 * access. These claims should propagate to all devices where the user is
461 * already signed in (after token expiration or when token refresh is forced)
462 * and the next time the user signs in. If a reserved OIDC claim name
463 * is used (sub, iat, iss, etc), an error is thrown. They are set on the
464 * authenticated user's ID token JWT.
465 *
466 * See {@link https://firebase.google.com/docs/auth/admin/custom-claims |
467 * Defining user roles and access levels}
468 * for code samples and detailed documentation.
469 *
470 * @param uid - The `uid` of the user to edit.
471 * @param customUserClaims - The developer claims to set. If null is
472 * passed, existing custom claims are deleted. Passing a custom claims payload
473 * larger than 1000 bytes will throw an error. Custom claims are added to the
474 * user's ID token which is transmitted on every authenticated request.
475 * For profile non-access related user attributes, use database or other
476 * separate storage systems.
477 * @returns A promise that resolves when the operation completes
478 * successfully.
479 */
480 setCustomUserClaims(uid, customUserClaims) {
481 return this.authRequestHandler.setCustomUserClaims(uid, customUserClaims)
482 .then(() => {
483 // Return nothing on success.
484 });
485 }
486 /**
487 * Revokes all refresh tokens for an existing user.
488 *
489 * This API will update the user's {@link UserRecord.tokensValidAfterTime} to
490 * the current UTC. It is important that the server on which this is called has
491 * its clock set correctly and synchronized.
492 *
493 * While this will revoke all sessions for a specified user and disable any
494 * new ID tokens for existing sessions from getting minted, existing ID tokens
495 * may remain active until their natural expiration (one hour). To verify that
496 * ID tokens are revoked, use {@link BaseAuth.verifyIdToken}
497 * where `checkRevoked` is set to true.
498 *
499 * @param uid - The `uid` corresponding to the user whose refresh tokens
500 * are to be revoked.
501 *
502 * @returns An empty promise fulfilled once the user's refresh
503 * tokens have been revoked.
504 */
505 revokeRefreshTokens(uid) {
506 return this.authRequestHandler.revokeRefreshTokens(uid)
507 .then(() => {
508 // Return nothing on success.
509 });
510 }
511 /**
512 * Imports the provided list of users into Firebase Auth.
513 * A maximum of 1000 users are allowed to be imported one at a time.
514 * When importing users with passwords,
515 * {@link UserImportOptions} are required to be
516 * specified.
517 * This operation is optimized for bulk imports and will ignore checks on `uid`,
518 * `email` and other identifier uniqueness which could result in duplications.
519 *
520 * @param users - The list of user records to import to Firebase Auth.
521 * @param options - The user import options, required when the users provided include
522 * password credentials.
523 * @returns A promise that resolves when
524 * the operation completes with the result of the import. This includes the
525 * number of successful imports, the number of failed imports and their
526 * corresponding errors.
527 */
528 importUsers(users, options) {
529 return this.authRequestHandler.uploadAccount(users, options);
530 }
531 /**
532 * Creates a new Firebase session cookie with the specified options. The created
533 * JWT string can be set as a server-side session cookie with a custom cookie
534 * policy, and be used for session management. The session cookie JWT will have
535 * the same payload claims as the provided ID token.
536 *
537 * See {@link https://firebase.google.com/docs/auth/admin/manage-cookies | Manage Session Cookies}
538 * for code samples and detailed documentation.
539 *
540 * @param idToken - The Firebase ID token to exchange for a session
541 * cookie.
542 * @param sessionCookieOptions - The session
543 * cookie options which includes custom session duration.
544 *
545 * @returns A promise that resolves on success with the
546 * created session cookie.
547 */
548 createSessionCookie(idToken, sessionCookieOptions) {
549 // Return rejected promise if expiresIn is not available.
550 if (!validator.isNonNullObject(sessionCookieOptions) ||
551 !validator.isNumber(sessionCookieOptions.expiresIn)) {
552 return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_SESSION_COOKIE_DURATION));
553 }
554 return this.authRequestHandler.createSessionCookie(idToken, sessionCookieOptions.expiresIn);
555 }
556 /**
557 * Verifies a Firebase session cookie. Returns a Promise with the cookie claims.
558 * Rejects the promise if the cookie could not be verified.
559 *
560 * If `checkRevoked` is set to true, first verifies whether the corresponding
561 * user is disabled: If yes, an `auth/user-disabled` error is thrown. If no,
562 * verifies if the session corresponding to the session cookie was revoked.
563 * If the corresponding user's session was invalidated, an
564 * `auth/session-cookie-revoked` error is thrown. If not specified the check
565 * is not performed.
566 *
567 * See {@link https://firebase.google.com/docs/auth/admin/manage-cookies#verify_session_cookie_and_check_permissions |
568 * Verify Session Cookies}
569 * for code samples and detailed documentation
570 *
571 * @param sessionCookie - The session cookie to verify.
572 * @param checkForRevocation - Whether to check if the session cookie was
573 * revoked. This requires an extra request to the Firebase Auth backend to
574 * check the `tokensValidAfterTime` time for the corresponding user.
575 * When not specified, this additional check is not performed.
576 *
577 * @returns A promise fulfilled with the
578 * session cookie's decoded claims if the session cookie is valid; otherwise,
579 * a rejected promise.
580 */
581 verifySessionCookie(sessionCookie, checkRevoked = false) {
582 const isEmulator = (0, auth_api_request_1.useEmulator)();
583 return this.sessionCookieVerifier.verifyJWT(sessionCookie, isEmulator)
584 .then((decodedIdToken) => {
585 // Whether to check if the token was revoked.
586 if (checkRevoked || isEmulator) {
587 return this.verifyDecodedJWTNotRevokedOrDisabled(decodedIdToken, error_1.AuthClientErrorCode.SESSION_COOKIE_REVOKED);
588 }
589 return decodedIdToken;
590 });
591 }
592 /**
593 * Generates the out of band email action link to reset a user's password.
594 * The link is generated for the user with the specified email address. The
595 * optional {@link ActionCodeSettings} object
596 * defines whether the link is to be handled by a mobile app or browser and the
597 * additional state information to be passed in the deep link, etc.
598 *
599 * @example
600 * ```javascript
601 * var actionCodeSettings = {
602 * url: 'https://www.example.com/?email=user@example.com',
603 * iOS: {
604 * bundleId: 'com.example.ios'
605 * },
606 * android: {
607 * packageName: 'com.example.android',
608 * installApp: true,
609 * minimumVersion: '12'
610 * },
611 * handleCodeInApp: true,
612 * dynamicLinkDomain: 'custom.page.link'
613 * };
614 * admin.auth()
615 * .generatePasswordResetLink('user@example.com', actionCodeSettings)
616 * .then(function(link) {
617 * // The link was successfully generated.
618 * })
619 * .catch(function(error) {
620 * // Some error occurred, you can inspect the code: error.code
621 * });
622 * ```
623 *
624 * @param email - The email address of the user whose password is to be
625 * reset.
626 * @param actionCodeSettings - The action
627 * code settings. If specified, the state/continue URL is set as the
628 * "continueUrl" parameter in the password reset link. The default password
629 * reset landing page will use this to display a link to go back to the app
630 * if it is installed.
631 * If the actionCodeSettings is not specified, no URL is appended to the
632 * action URL.
633 * The state URL provided must belong to a domain that is whitelisted by the
634 * developer in the console. Otherwise an error is thrown.
635 * Mobile app redirects are only applicable if the developer configures
636 * and accepts the Firebase Dynamic Links terms of service.
637 * The Android package name and iOS bundle ID are respected only if they
638 * are configured in the same Firebase Auth project.
639 * @returns A promise that resolves with the generated link.
640 */
641 generatePasswordResetLink(email, actionCodeSettings) {
642 return this.authRequestHandler.getEmailActionLink('PASSWORD_RESET', email, actionCodeSettings);
643 }
644 /**
645 * Generates the out of band email action link to verify the user's ownership
646 * of the specified email. The {@link ActionCodeSettings} object provided
647 * as an argument to this method defines whether the link is to be handled by a
648 * mobile app or browser along with additional state information to be passed in
649 * the deep link, etc.
650 *
651 * @example
652 * ```javascript
653 * var actionCodeSettings = {
654 * url: 'https://www.example.com/cart?email=user@example.com&cartId=123',
655 * iOS: {
656 * bundleId: 'com.example.ios'
657 * },
658 * android: {
659 * packageName: 'com.example.android',
660 * installApp: true,
661 * minimumVersion: '12'
662 * },
663 * handleCodeInApp: true,
664 * dynamicLinkDomain: 'custom.page.link'
665 * };
666 * admin.auth()
667 * .generateEmailVerificationLink('user@example.com', actionCodeSettings)
668 * .then(function(link) {
669 * // The link was successfully generated.
670 * })
671 * .catch(function(error) {
672 * // Some error occurred, you can inspect the code: error.code
673 * });
674 * ```
675 *
676 * @param email - The email account to verify.
677 * @param actionCodeSettings - The action
678 * code settings. If specified, the state/continue URL is set as the
679 * "continueUrl" parameter in the email verification link. The default email
680 * verification landing page will use this to display a link to go back to
681 * the app if it is installed.
682 * If the actionCodeSettings is not specified, no URL is appended to the
683 * action URL.
684 * The state URL provided must belong to a domain that is whitelisted by the
685 * developer in the console. Otherwise an error is thrown.
686 * Mobile app redirects are only applicable if the developer configures
687 * and accepts the Firebase Dynamic Links terms of service.
688 * The Android package name and iOS bundle ID are respected only if they
689 * are configured in the same Firebase Auth project.
690 * @returns A promise that resolves with the generated link.
691 */
692 generateEmailVerificationLink(email, actionCodeSettings) {
693 return this.authRequestHandler.getEmailActionLink('VERIFY_EMAIL', email, actionCodeSettings);
694 }
695 /**
696 * Generates an out-of-band email action link to verify the user's ownership
697 * of the specified email. The {@link ActionCodeSettings} object provided
698 * as an argument to this method defines whether the link is to be handled by a
699 * mobile app or browser along with additional state information to be passed in
700 * the deep link, etc.
701 *
702 * @param email - The current email account.
703 * @param newEmail - The email address the account is being updated to.
704 * @param actionCodeSettings - The action
705 * code settings. If specified, the state/continue URL is set as the
706 * "continueUrl" parameter in the email verification link. The default email
707 * verification landing page will use this to display a link to go back to
708 * the app if it is installed.
709 * If the actionCodeSettings is not specified, no URL is appended to the
710 * action URL.
711 * The state URL provided must belong to a domain that is authorized
712 * in the console, or an error will be thrown.
713 * Mobile app redirects are only applicable if the developer configures
714 * and accepts the Firebase Dynamic Links terms of service.
715 * The Android package name and iOS bundle ID are respected only if they
716 * are configured in the same Firebase Auth project.
717 * @returns A promise that resolves with the generated link.
718 */
719 generateVerifyAndChangeEmailLink(email, newEmail, actionCodeSettings) {
720 return this.authRequestHandler.getEmailActionLink('VERIFY_AND_CHANGE_EMAIL', email, actionCodeSettings, newEmail);
721 }
722 /**
723 * Generates the out of band email action link to verify the user's ownership
724 * of the specified email. The {@link ActionCodeSettings} object provided
725 * as an argument to this method defines whether the link is to be handled by a
726 * mobile app or browser along with additional state information to be passed in
727 * the deep link, etc.
728 *
729 * @example
730 * ```javascript
731 * var actionCodeSettings = {
732 * url: 'https://www.example.com/cart?email=user@example.com&cartId=123',
733 * iOS: {
734 * bundleId: 'com.example.ios'
735 * },
736 * android: {
737 * packageName: 'com.example.android',
738 * installApp: true,
739 * minimumVersion: '12'
740 * },
741 * handleCodeInApp: true,
742 * dynamicLinkDomain: 'custom.page.link'
743 * };
744 * admin.auth()
745 * .generateEmailVerificationLink('user@example.com', actionCodeSettings)
746 * .then(function(link) {
747 * // The link was successfully generated.
748 * })
749 * .catch(function(error) {
750 * // Some error occurred, you can inspect the code: error.code
751 * });
752 * ```
753 *
754 * @param email - The email account to verify.
755 * @param actionCodeSettings - The action
756 * code settings. If specified, the state/continue URL is set as the
757 * "continueUrl" parameter in the email verification link. The default email
758 * verification landing page will use this to display a link to go back to
759 * the app if it is installed.
760 * If the actionCodeSettings is not specified, no URL is appended to the
761 * action URL.
762 * The state URL provided must belong to a domain that is whitelisted by the
763 * developer in the console. Otherwise an error is thrown.
764 * Mobile app redirects are only applicable if the developer configures
765 * and accepts the Firebase Dynamic Links terms of service.
766 * The Android package name and iOS bundle ID are respected only if they
767 * are configured in the same Firebase Auth project.
768 * @returns A promise that resolves with the generated link.
769 */
770 generateSignInWithEmailLink(email, actionCodeSettings) {
771 return this.authRequestHandler.getEmailActionLink('EMAIL_SIGNIN', email, actionCodeSettings);
772 }
773 /**
774 * Returns the list of existing provider configurations matching the filter
775 * provided. At most, 100 provider configs can be listed at a time.
776 *
777 * SAML and OIDC provider support requires Google Cloud's Identity Platform
778 * (GCIP). To learn more about GCIP, including pricing and features,
779 * see the {@link https://cloud.google.com/identity-platform | GCIP documentation}.
780 *
781 * @param options - The provider config filter to apply.
782 * @returns A promise that resolves with the list of provider configs meeting the
783 * filter requirements.
784 */
785 listProviderConfigs(options) {
786 const processResponse = (response, providerConfigs) => {
787 // Return list of provider configuration and the next page token if available.
788 const result = {
789 providerConfigs,
790 };
791 // Delete result.pageToken if undefined.
792 if (Object.prototype.hasOwnProperty.call(response, 'nextPageToken')) {
793 result.pageToken = response.nextPageToken;
794 }
795 return result;
796 };
797 if (options && options.type === 'oidc') {
798 return this.authRequestHandler.listOAuthIdpConfigs(options.maxResults, options.pageToken)
799 .then((response) => {
800 // List of provider configurations to return.
801 const providerConfigs = [];
802 // Convert each provider config response to a OIDCConfig.
803 response.oauthIdpConfigs.forEach((configResponse) => {
804 providerConfigs.push(new auth_config_1.OIDCConfig(configResponse));
805 });
806 // Return list of provider configuration and the next page token if available.
807 return processResponse(response, providerConfigs);
808 });
809 }
810 else if (options && options.type === 'saml') {
811 return this.authRequestHandler.listInboundSamlConfigs(options.maxResults, options.pageToken)
812 .then((response) => {
813 // List of provider configurations to return.
814 const providerConfigs = [];
815 // Convert each provider config response to a SAMLConfig.
816 response.inboundSamlConfigs.forEach((configResponse) => {
817 providerConfigs.push(new auth_config_1.SAMLConfig(configResponse));
818 });
819 // Return list of provider configuration and the next page token if available.
820 return processResponse(response, providerConfigs);
821 });
822 }
823 return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '"AuthProviderConfigFilter.type" must be either "saml" or "oidc"'));
824 }
825 /**
826 * Looks up an Auth provider configuration by the provided ID.
827 * Returns a promise that resolves with the provider configuration
828 * corresponding to the provider ID specified. If the specified ID does not
829 * exist, an `auth/configuration-not-found` error is thrown.
830 *
831 * SAML and OIDC provider support requires Google Cloud's Identity Platform
832 * (GCIP). To learn more about GCIP, including pricing and features,
833 * see the {@link https://cloud.google.com/identity-platform | GCIP documentation}.
834 *
835 * @param providerId - The provider ID corresponding to the provider
836 * config to return.
837 * @returns A promise that resolves
838 * with the configuration corresponding to the provided ID.
839 */
840 getProviderConfig(providerId) {
841 if (auth_config_1.OIDCConfig.isProviderId(providerId)) {
842 return this.authRequestHandler.getOAuthIdpConfig(providerId)
843 .then((response) => {
844 return new auth_config_1.OIDCConfig(response);
845 });
846 }
847 else if (auth_config_1.SAMLConfig.isProviderId(providerId)) {
848 return this.authRequestHandler.getInboundSamlConfig(providerId)
849 .then((response) => {
850 return new auth_config_1.SAMLConfig(response);
851 });
852 }
853 return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID));
854 }
855 /**
856 * Deletes the provider configuration corresponding to the provider ID passed.
857 * If the specified ID does not exist, an `auth/configuration-not-found` error
858 * is thrown.
859 *
860 * SAML and OIDC provider support requires Google Cloud's Identity Platform
861 * (GCIP). To learn more about GCIP, including pricing and features,
862 * see the {@link https://cloud.google.com/identity-platform | GCIP documentation}.
863 *
864 * @param providerId - The provider ID corresponding to the provider
865 * config to delete.
866 * @returns A promise that resolves on completion.
867 */
868 deleteProviderConfig(providerId) {
869 if (auth_config_1.OIDCConfig.isProviderId(providerId)) {
870 return this.authRequestHandler.deleteOAuthIdpConfig(providerId);
871 }
872 else if (auth_config_1.SAMLConfig.isProviderId(providerId)) {
873 return this.authRequestHandler.deleteInboundSamlConfig(providerId);
874 }
875 return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID));
876 }
877 /**
878 * Returns a promise that resolves with the updated `AuthProviderConfig`
879 * corresponding to the provider ID specified.
880 * If the specified ID does not exist, an `auth/configuration-not-found` error
881 * is thrown.
882 *
883 * SAML and OIDC provider support requires Google Cloud's Identity Platform
884 * (GCIP). To learn more about GCIP, including pricing and features,
885 * see the {@link https://cloud.google.com/identity-platform | GCIP documentation}.
886 *
887 * @param providerId - The provider ID corresponding to the provider
888 * config to update.
889 * @param updatedConfig - The updated configuration.
890 * @returns A promise that resolves with the updated provider configuration.
891 */
892 updateProviderConfig(providerId, updatedConfig) {
893 if (!validator.isNonNullObject(updatedConfig)) {
894 return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, 'Request is missing "UpdateAuthProviderRequest" configuration.'));
895 }
896 if (auth_config_1.OIDCConfig.isProviderId(providerId)) {
897 return this.authRequestHandler.updateOAuthIdpConfig(providerId, updatedConfig)
898 .then((response) => {
899 return new auth_config_1.OIDCConfig(response);
900 });
901 }
902 else if (auth_config_1.SAMLConfig.isProviderId(providerId)) {
903 return this.authRequestHandler.updateInboundSamlConfig(providerId, updatedConfig)
904 .then((response) => {
905 return new auth_config_1.SAMLConfig(response);
906 });
907 }
908 return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID));
909 }
910 /**
911 * Returns a promise that resolves with the newly created `AuthProviderConfig`
912 * when the new provider configuration is created.
913 *
914 * SAML and OIDC provider support requires Google Cloud's Identity Platform
915 * (GCIP). To learn more about GCIP, including pricing and features,
916 * see the {@link https://cloud.google.com/identity-platform | GCIP documentation}.
917 *
918 * @param config - The provider configuration to create.
919 * @returns A promise that resolves with the created provider configuration.
920 */
921 createProviderConfig(config) {
922 if (!validator.isNonNullObject(config)) {
923 return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, 'Request is missing "AuthProviderConfig" configuration.'));
924 }
925 if (auth_config_1.OIDCConfig.isProviderId(config.providerId)) {
926 return this.authRequestHandler.createOAuthIdpConfig(config)
927 .then((response) => {
928 return new auth_config_1.OIDCConfig(response);
929 });
930 }
931 else if (auth_config_1.SAMLConfig.isProviderId(config.providerId)) {
932 return this.authRequestHandler.createInboundSamlConfig(config)
933 .then((response) => {
934 return new auth_config_1.SAMLConfig(response);
935 });
936 }
937 return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID));
938 }
939 /** @alpha */
940 // eslint-disable-next-line @typescript-eslint/naming-convention
941 _verifyAuthBlockingToken(token, audience) {
942 const isEmulator = (0, auth_api_request_1.useEmulator)();
943 return this.authBlockingTokenVerifier._verifyAuthBlockingToken(token, isEmulator, audience)
944 .then((decodedAuthBlockingToken) => {
945 return decodedAuthBlockingToken;
946 });
947 }
948 /**
949 * Verifies the decoded Firebase issued JWT is not revoked or disabled. Returns a promise that
950 * resolves with the decoded claims on success. Rejects the promise with revocation error if revoked
951 * or user disabled.
952 *
953 * @param decodedIdToken - The JWT's decoded claims.
954 * @param revocationErrorInfo - The revocation error info to throw on revocation
955 * detection.
956 * @returns A promise that will be fulfilled after a successful verification.
957 */
958 verifyDecodedJWTNotRevokedOrDisabled(decodedIdToken, revocationErrorInfo) {
959 // Get tokens valid after time for the corresponding user.
960 return this.getUser(decodedIdToken.sub)
961 .then((user) => {
962 if (user.disabled) {
963 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.USER_DISABLED, 'The user record is disabled.');
964 }
965 // If no tokens valid after time available, token is not revoked.
966 if (user.tokensValidAfterTime) {
967 // Get the ID token authentication time and convert to milliseconds UTC.
968 const authTimeUtc = decodedIdToken.auth_time * 1000;
969 // Get user tokens valid after time in milliseconds UTC.
970 const validSinceUtc = new Date(user.tokensValidAfterTime).getTime();
971 // Check if authentication time is older than valid since time.
972 if (authTimeUtc < validSinceUtc) {
973 throw new error_1.FirebaseAuthError(revocationErrorInfo);
974 }
975 }
976 // All checks above passed. Return the decoded token.
977 return decodedIdToken;
978 });
979 }
980}
981exports.BaseAuth = BaseAuth;