base-auth.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. /*! firebase-admin v12.1.1 */
  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. */
  18. Object.defineProperty(exports, "__esModule", { value: true });
  19. exports.BaseAuth = exports.createFirebaseTokenGenerator = void 0;
  20. const error_1 = require("../utils/error");
  21. const deep_copy_1 = require("../utils/deep-copy");
  22. const validator = require("../utils/validator");
  23. const auth_api_request_1 = require("./auth-api-request");
  24. const token_generator_1 = require("./token-generator");
  25. const token_verifier_1 = require("./token-verifier");
  26. const auth_config_1 = require("./auth-config");
  27. const user_record_1 = require("./user-record");
  28. const identifier_1 = require("./identifier");
  29. const crypto_signer_1 = require("../utils/crypto-signer");
  30. /**
  31. * @internal
  32. */
  33. function 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. }
  42. exports.createFirebaseTokenGenerator = createFirebaseTokenGenerator;
  43. /**
  44. * Common parent interface for both `Auth` and `TenantAwareAuth` APIs.
  45. */
  46. class 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. }
  981. exports.BaseAuth = BaseAuth;