Edit File: auth.js
/*! firebase-admin v9.12.0 */ "use strict"; /*! * @license * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.Auth = exports.TenantAwareAuth = exports.BaseAuth = void 0; var deep_copy_1 = require("../utils/deep-copy"); var user_record_1 = require("./user-record"); var identifier_1 = require("./identifier"); var token_generator_1 = require("./token-generator"); var auth_api_request_1 = require("./auth-api-request"); var error_1 = require("../utils/error"); var utils = require("../utils/index"); var validator = require("../utils/validator"); var token_verifier_1 = require("./token-verifier"); var auth_config_1 = require("./auth-config"); var tenant_manager_1 = require("./tenant-manager"); var crypto_signer_1 = require("../utils/crypto-signer"); /** * Base Auth class. Mainly used for user management APIs. */ var BaseAuth = /** @class */ (function () { /** * The BaseAuth class constructor. * * @param app The FirebaseApp to associate with this Auth instance. * @param authRequestHandler The RPC request handler for this instance. * @param tokenGenerator Optional token generator. If not specified, a * (non-tenant-aware) instance will be created. Use this paramter to * specify a tenant-aware tokenGenerator. * @constructor */ function BaseAuth(app, authRequestHandler, tokenGenerator) { this.authRequestHandler = authRequestHandler; if (tokenGenerator) { this.tokenGenerator = tokenGenerator; } else { this.tokenGenerator = createFirebaseTokenGenerator(app); } this.sessionCookieVerifier = token_verifier_1.createSessionCookieVerifier(app); this.idTokenVerifier = token_verifier_1.createIdTokenVerifier(app); } /** * Creates a new custom token that can be sent back to a client to use with * signInWithCustomToken(). * * @param {string} uid The uid to use as the JWT subject. * @param {object=} developerClaims Optional additional claims to include in the JWT payload. * * @return {Promise<string>} A JWT for the provided payload. */ BaseAuth.prototype.createCustomToken = function (uid, developerClaims) { return this.tokenGenerator.createCustomToken(uid, developerClaims); }; /** * Verifies a JWT auth token. Returns a promise with the token‘s claims. * Rejects the promise if the token cannot be verified. * If `checkRevoked` is set to true, first verifies whether the corresponding * user is disabled. * If yes, an `auth/user-disabled` error is thrown. * If no, verifies if the session corresponding to the ID token was revoked. * If the corresponding user's session was invalidated, an * `auth/id-token-revoked` error is thrown. * If not specified the check is not applied. * * @param {string} idToken The JWT to verify. * @param {boolean=} checkRevoked Whether to check if the ID token is revoked. * @return {Promise<DecodedIdToken>} A promise that will be fulfilled after * a successful verification. */ BaseAuth.prototype.verifyIdToken = function (idToken, checkRevoked) { var _this = this; if (checkRevoked === void 0) { checkRevoked = false; } var isEmulator = auth_api_request_1.useEmulator(); return this.idTokenVerifier.verifyJWT(idToken, isEmulator) .then(function (decodedIdToken) { // Whether to check if the token was revoked. if (checkRevoked || isEmulator) { return _this.verifyDecodedJWTNotRevokedOrDisabled(decodedIdToken, error_1.AuthClientErrorCode.ID_TOKEN_REVOKED); } return decodedIdToken; }); }; /** * Looks up the user identified by the provided user id and returns a promise that is * fulfilled with a user record for the given user if that user is found. * * @param {string} uid The uid of the user to look up. * @return {Promise<UserRecord>} A promise that resolves with the corresponding user record. */ BaseAuth.prototype.getUser = function (uid) { return this.authRequestHandler.getAccountInfoByUid(uid) .then(function (response) { // Returns the user record populated with server response. return new user_record_1.UserRecord(response.users[0]); }); }; /** * Looks up the user identified by the provided email and returns a promise that is * fulfilled with a user record for the given user if that user is found. * * @param {string} email The email of the user to look up. * @return {Promise<UserRecord>} A promise that resolves with the corresponding user record. */ BaseAuth.prototype.getUserByEmail = function (email) { return this.authRequestHandler.getAccountInfoByEmail(email) .then(function (response) { // Returns the user record populated with server response. return new user_record_1.UserRecord(response.users[0]); }); }; /** * Looks up the user identified by the provided phone number and returns a promise that is * fulfilled with a user record for the given user if that user is found. * * @param {string} phoneNumber The phone number of the user to look up. * @return {Promise<UserRecord>} A promise that resolves with the corresponding user record. */ BaseAuth.prototype.getUserByPhoneNumber = function (phoneNumber) { return this.authRequestHandler.getAccountInfoByPhoneNumber(phoneNumber) .then(function (response) { // Returns the user record populated with server response. return new user_record_1.UserRecord(response.users[0]); }); }; /** * Gets the user data for the user corresponding to a given provider id. * * See [Retrieve user data](/docs/auth/admin/manage-users#retrieve_user_data) * for code samples and detailed documentation. * * @param providerId The provider ID, for example, "google.com" for the * Google provider. * @param uid The user identifier for the given provider. * * @return A promise fulfilled with the user data corresponding to the * given provider id. */ BaseAuth.prototype.getUserByProviderUid = function (providerId, uid) { // Although we don't really advertise it, we want to also handle // non-federated idps with this call. So if we detect one of them, we'll // reroute this request appropriately. if (providerId === 'phone') { return this.getUserByPhoneNumber(uid); } else if (providerId === 'email') { return this.getUserByEmail(uid); } return this.authRequestHandler.getAccountInfoByFederatedUid(providerId, uid) .then(function (response) { // Returns the user record populated with server response. return new user_record_1.UserRecord(response.users[0]); }); }; /** * Gets the user data corresponding to the specified identifiers. * * There are no ordering guarantees; in particular, the nth entry in the result list is not * guaranteed to correspond to the nth entry in the input parameters list. * * Only a maximum of 100 identifiers may be supplied. If more than 100 identifiers are supplied, * this method will immediately throw a FirebaseAuthError. * * @param identifiers The identifiers used to indicate which user records should be returned. Must * have <= 100 entries. * @return {Promise<GetUsersResult>} A promise that resolves to the corresponding user records. * @throws FirebaseAuthError If any of the identifiers are invalid or if more than 100 * identifiers are specified. */ BaseAuth.prototype.getUsers = function (identifiers) { if (!validator.isArray(identifiers)) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '`identifiers` parameter must be an array'); } return this.authRequestHandler .getAccountInfoByIdentifiers(identifiers) .then(function (response) { /** * Checks if the specified identifier is within the list of * UserRecords. */ var isUserFound = (function (id, userRecords) { return !!userRecords.find(function (userRecord) { if (identifier_1.isUidIdentifier(id)) { return id.uid === userRecord.uid; } else if (identifier_1.isEmailIdentifier(id)) { return id.email === userRecord.email; } else if (identifier_1.isPhoneIdentifier(id)) { return id.phoneNumber === userRecord.phoneNumber; } else if (identifier_1.isProviderIdentifier(id)) { var matchingUserInfo = userRecord.providerData.find(function (userInfo) { return id.providerId === userInfo.providerId; }); return !!matchingUserInfo && id.providerUid === matchingUserInfo.uid; } else { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'Unhandled identifier type'); } }); }); var users = response.users ? response.users.map(function (user) { return new user_record_1.UserRecord(user); }) : []; var notFound = identifiers.filter(function (id) { return !isUserFound(id, users); }); return { users: users, notFound: notFound }; }); }; /** * Exports a batch of user accounts. Batch size is determined by the maxResults argument. * Starting point of the batch is determined by the pageToken argument. * * @param {number=} maxResults The page size, 1000 if undefined. This is also the maximum * allowed limit. * @param {string=} pageToken The next page token. If not specified, returns users starting * without any offset. * @return {Promise<{users: UserRecord[], pageToken?: string}>} A promise that resolves with * the current batch of downloaded users and the next page token. For the last page, an * empty list of users and no page token are returned. */ BaseAuth.prototype.listUsers = function (maxResults, pageToken) { return this.authRequestHandler.downloadAccount(maxResults, pageToken) .then(function (response) { // List of users to return. var users = []; // Convert each user response to a UserRecord. response.users.forEach(function (userResponse) { users.push(new user_record_1.UserRecord(userResponse)); }); // Return list of user records and the next page token if available. var result = { users: users, pageToken: response.nextPageToken, }; // Delete result.pageToken if undefined. if (typeof result.pageToken === 'undefined') { delete result.pageToken; } return result; }); }; /** * Creates a new user with the properties provided. * * @param {CreateRequest} properties The properties to set on the new user record to be created. * @return {Promise<UserRecord>} A promise that resolves with the newly created user record. */ BaseAuth.prototype.createUser = function (properties) { var _this = this; return this.authRequestHandler.createNewAccount(properties) .then(function (uid) { // Return the corresponding user record. return _this.getUser(uid); }) .catch(function (error) { if (error.code === 'auth/user-not-found') { // Something must have happened after creating the user and then retrieving it. throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'Unable to create the user record provided.'); } throw error; }); }; /** * Deletes the user identified by the provided user id and returns a promise that is * fulfilled when the user is found and successfully deleted. * * @param {string} uid The uid of the user to delete. * @return {Promise<void>} A promise that resolves when the user is successfully deleted. */ BaseAuth.prototype.deleteUser = function (uid) { return this.authRequestHandler.deleteAccount(uid) .then(function () { // Return nothing on success. }); }; BaseAuth.prototype.deleteUsers = function (uids) { if (!validator.isArray(uids)) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '`uids` parameter must be an array'); } return this.authRequestHandler.deleteAccounts(uids, /*force=*/ true) .then(function (batchDeleteAccountsResponse) { var result = { failureCount: 0, successCount: uids.length, errors: [], }; if (!validator.isNonEmptyArray(batchDeleteAccountsResponse.errors)) { return result; } result.failureCount = batchDeleteAccountsResponse.errors.length; result.successCount = uids.length - batchDeleteAccountsResponse.errors.length; result.errors = batchDeleteAccountsResponse.errors.map(function (batchDeleteErrorInfo) { if (batchDeleteErrorInfo.index === undefined) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'Corrupt BatchDeleteAccountsResponse detected'); } var errMsgToError = function (msg) { // We unconditionally set force=true, so the 'NOT_DISABLED' error // should not be possible. var code = msg && msg.startsWith('NOT_DISABLED') ? error_1.AuthClientErrorCode.USER_NOT_DISABLED : error_1.AuthClientErrorCode.INTERNAL_ERROR; return new error_1.FirebaseAuthError(code, batchDeleteErrorInfo.message); }; return { index: batchDeleteErrorInfo.index, error: errMsgToError(batchDeleteErrorInfo.message), }; }); return result; }); }; /** * Updates an existing user with the properties provided. * * @param {string} uid The uid identifier of the user to update. * @param {UpdateRequest} properties The properties to update on the existing user. * @return {Promise<UserRecord>} A promise that resolves with the modified user record. */ BaseAuth.prototype.updateUser = function (uid, properties) { var _this = this; // Although we don't really advertise it, we want to also handle linking of // non-federated idps with this call. So if we detect one of them, we'll // adjust the properties parameter appropriately. This *does* imply that a // conflict could arise, e.g. if the user provides a phoneNumber property, // but also provides a providerToLink with a 'phone' provider id. In that // case, we'll throw an error. properties = deep_copy_1.deepCopy(properties); if (properties === null || properties === void 0 ? void 0 : properties.providerToLink) { if (properties.providerToLink.providerId === 'email') { if (typeof properties.email !== 'undefined') { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, "Both UpdateRequest.email and UpdateRequest.providerToLink.providerId='email' were set. To " + 'link to the email/password provider, only specify the UpdateRequest.email field.'); } properties.email = properties.providerToLink.uid; delete properties.providerToLink; } else if (properties.providerToLink.providerId === 'phone') { if (typeof properties.phoneNumber !== 'undefined') { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, "Both UpdateRequest.phoneNumber and UpdateRequest.providerToLink.providerId='phone' were set. To " + 'link to a phone provider, only specify the UpdateRequest.phoneNumber field.'); } properties.phoneNumber = properties.providerToLink.uid; delete properties.providerToLink; } } if (properties === null || properties === void 0 ? void 0 : properties.providersToUnlink) { if (properties.providersToUnlink.indexOf('phone') !== -1) { // If we've been told to unlink the phone provider both via setting // phoneNumber to null *and* by setting providersToUnlink to include // 'phone', then we'll reject that. Though it might also be reasonable // to relax this restriction and just unlink it. if (properties.phoneNumber === null) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, "Both UpdateRequest.phoneNumber=null and UpdateRequest.providersToUnlink=['phone'] were set. To " + 'unlink from a phone provider, only specify the UpdateRequest.phoneNumber=null field.'); } } } return this.authRequestHandler.updateExistingAccount(uid, properties) .then(function (existingUid) { // Return the corresponding user record. return _this.getUser(existingUid); }); }; /** * Sets additional developer claims on an existing user identified by the provided UID. * * @param {string} uid The user to edit. * @param {object} customUserClaims The developer claims to set. * @return {Promise<void>} A promise that resolves when the operation completes * successfully. */ BaseAuth.prototype.setCustomUserClaims = function (uid, customUserClaims) { return this.authRequestHandler.setCustomUserClaims(uid, customUserClaims) .then(function () { // Return nothing on success. }); }; /** * Revokes all refresh tokens for the specified user identified by the provided UID. * In addition to revoking all refresh tokens for a user, all ID tokens issued before * revocation will also be revoked on the Auth backend. Any request with an ID token * generated before revocation will be rejected with a token expired error. * * @param {string} uid The user whose tokens are to be revoked. * @return {Promise<void>} A promise that resolves when the operation completes * successfully. */ BaseAuth.prototype.revokeRefreshTokens = function (uid) { return this.authRequestHandler.revokeRefreshTokens(uid) .then(function () { // Return nothing on success. }); }; /** * Imports the list of users provided to Firebase Auth. This is useful when * migrating from an external authentication system without having to use the Firebase CLI SDK. * At most, 1000 users are allowed to be imported one at a time. * When importing a list of password users, UserImportOptions are required to be specified. * * @param {UserImportRecord[]} users The list of user records to import to Firebase Auth. * @param {UserImportOptions=} options The user import options, required when the users provided * include password credentials. * @return {Promise<UserImportResult>} A promise that resolves when the operation completes * with the result of the import. This includes the number of successful imports, the number * of failed uploads and their corresponding errors. */ BaseAuth.prototype.importUsers = function (users, options) { return this.authRequestHandler.uploadAccount(users, options); }; /** * Creates a new Firebase session cookie with the specified options that can be used for * session management (set as a server side session cookie with custom cookie policy). * The session cookie JWT will have the same payload claims as the provided ID token. * * @param {string} idToken The Firebase ID token to exchange for a session cookie. * @param {SessionCookieOptions} sessionCookieOptions The session cookie options which includes * custom session duration. * * @return {Promise<string>} A promise that resolves on success with the created session cookie. */ BaseAuth.prototype.createSessionCookie = function (idToken, sessionCookieOptions) { // Return rejected promise if expiresIn is not available. if (!validator.isNonNullObject(sessionCookieOptions) || !validator.isNumber(sessionCookieOptions.expiresIn)) { return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_SESSION_COOKIE_DURATION)); } return this.authRequestHandler.createSessionCookie(idToken, sessionCookieOptions.expiresIn); }; /** * Verifies a Firebase session cookie. Returns a promise with the token’s claims. * Rejects the promise if the cookie could not be verified. * If `checkRevoked` is set to true, first verifies whether the corresponding * user is disabled: * If yes, an `auth/user-disabled` error is thrown. * If no, verifies if the session corresponding to the session cookie was * revoked. * If the corresponding user's session was invalidated, an * `auth/session-cookie-revoked` error is thrown. * If not specified the check is not performed. * * @param {string} sessionCookie The session cookie to verify. * @param {boolean=} checkRevoked Whether to check if the session cookie is * revoked. * @return {Promise<DecodedIdToken>} A promise that will be fulfilled after * a successful verification. */ BaseAuth.prototype.verifySessionCookie = function (sessionCookie, checkRevoked) { var _this = this; if (checkRevoked === void 0) { checkRevoked = false; } var isEmulator = auth_api_request_1.useEmulator(); return this.sessionCookieVerifier.verifyJWT(sessionCookie, isEmulator) .then(function (decodedIdToken) { // Whether to check if the cookie was revoked. if (checkRevoked || isEmulator) { return _this.verifyDecodedJWTNotRevokedOrDisabled(decodedIdToken, error_1.AuthClientErrorCode.SESSION_COOKIE_REVOKED); } return decodedIdToken; }); }; /** * Generates the out of band email action link for password reset flows for the * email specified using the action code settings provided. * Returns a promise that resolves with the generated link. * * @param {string} email The email of the user whose password is to be reset. * @param {ActionCodeSettings=} actionCodeSettings The optional action code setings which defines whether * the link is to be handled by a mobile app and the additional state information to be passed in the * deep link, etc. * @return {Promise<string>} A promise that resolves with the password reset link. */ BaseAuth.prototype.generatePasswordResetLink = function (email, actionCodeSettings) { return this.authRequestHandler.getEmailActionLink('PASSWORD_RESET', email, actionCodeSettings); }; /** * Generates the out of band email action link for email verification flows for the * email specified using the action code settings provided. * Returns a promise that resolves with the generated link. * * @param {string} email The email of the user to be verified. * @param {ActionCodeSettings=} actionCodeSettings The optional action code setings which defines whether * the link is to be handled by a mobile app and the additional state information to be passed in the * deep link, etc. * @return {Promise<string>} A promise that resolves with the email verification link. */ BaseAuth.prototype.generateEmailVerificationLink = function (email, actionCodeSettings) { return this.authRequestHandler.getEmailActionLink('VERIFY_EMAIL', email, actionCodeSettings); }; /** * Generates the out of band email action link for email link sign-in flows for the * email specified using the action code settings provided. * Returns a promise that resolves with the generated link. * * @param {string} email The email of the user signing in. * @param {ActionCodeSettings} actionCodeSettings The required action code setings which defines whether * the link is to be handled by a mobile app and the additional state information to be passed in the * deep link, etc. * @return {Promise<string>} A promise that resolves with the email sign-in link. */ BaseAuth.prototype.generateSignInWithEmailLink = function (email, actionCodeSettings) { return this.authRequestHandler.getEmailActionLink('EMAIL_SIGNIN', email, actionCodeSettings); }; /** * Returns the list of existing provider configuation matching the filter provided. * At most, 100 provider configs are allowed to be imported at a time. * * @param {AuthProviderConfigFilter} options The provider config filter to apply. * @return {Promise<ListProviderConfigResults>} A promise that resolves with the list of provider configs * meeting the filter requirements. */ BaseAuth.prototype.listProviderConfigs = function (options) { var processResponse = function (response, providerConfigs) { // Return list of provider configuration and the next page token if available. var result = { providerConfigs: providerConfigs, }; // Delete result.pageToken if undefined. if (Object.prototype.hasOwnProperty.call(response, 'nextPageToken')) { result.pageToken = response.nextPageToken; } return result; }; if (options && options.type === 'oidc') { return this.authRequestHandler.listOAuthIdpConfigs(options.maxResults, options.pageToken) .then(function (response) { // List of provider configurations to return. var providerConfigs = []; // Convert each provider config response to a OIDCConfig. response.oauthIdpConfigs.forEach(function (configResponse) { providerConfigs.push(new auth_config_1.OIDCConfig(configResponse)); }); // Return list of provider configuration and the next page token if available. return processResponse(response, providerConfigs); }); } else if (options && options.type === 'saml') { return this.authRequestHandler.listInboundSamlConfigs(options.maxResults, options.pageToken) .then(function (response) { // List of provider configurations to return. var providerConfigs = []; // Convert each provider config response to a SAMLConfig. response.inboundSamlConfigs.forEach(function (configResponse) { providerConfigs.push(new auth_config_1.SAMLConfig(configResponse)); }); // Return list of provider configuration and the next page token if available. return processResponse(response, providerConfigs); }); } return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '"AuthProviderConfigFilter.type" must be either "saml" or "oidc"')); }; /** * Looks up an Auth provider configuration by ID. * Returns a promise that resolves with the provider configuration corresponding to the provider ID specified. * * @param {string} providerId The provider ID corresponding to the provider config to return. * @return {Promise<AuthProviderConfig>} */ BaseAuth.prototype.getProviderConfig = function (providerId) { if (auth_config_1.OIDCConfig.isProviderId(providerId)) { return this.authRequestHandler.getOAuthIdpConfig(providerId) .then(function (response) { return new auth_config_1.OIDCConfig(response); }); } else if (auth_config_1.SAMLConfig.isProviderId(providerId)) { return this.authRequestHandler.getInboundSamlConfig(providerId) .then(function (response) { return new auth_config_1.SAMLConfig(response); }); } return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID)); }; /** * Deletes the provider configuration corresponding to the provider ID passed. * * @param {string} providerId The provider ID corresponding to the provider config to delete. * @return {Promise<void>} A promise that resolves on completion. */ BaseAuth.prototype.deleteProviderConfig = function (providerId) { if (auth_config_1.OIDCConfig.isProviderId(providerId)) { return this.authRequestHandler.deleteOAuthIdpConfig(providerId); } else if (auth_config_1.SAMLConfig.isProviderId(providerId)) { return this.authRequestHandler.deleteInboundSamlConfig(providerId); } return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID)); }; /** * Returns a promise that resolves with the updated AuthProviderConfig when the provider configuration corresponding * to the provider ID specified is updated with the specified configuration. * * @param {string} providerId The provider ID corresponding to the provider config to update. * @param {UpdateAuthProviderRequest} updatedConfig The updated configuration. * @return {Promise<AuthProviderConfig>} A promise that resolves with the updated provider configuration. */ BaseAuth.prototype.updateProviderConfig = function (providerId, updatedConfig) { if (!validator.isNonNullObject(updatedConfig)) { return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, 'Request is missing "UpdateAuthProviderRequest" configuration.')); } if (auth_config_1.OIDCConfig.isProviderId(providerId)) { return this.authRequestHandler.updateOAuthIdpConfig(providerId, updatedConfig) .then(function (response) { return new auth_config_1.OIDCConfig(response); }); } else if (auth_config_1.SAMLConfig.isProviderId(providerId)) { return this.authRequestHandler.updateInboundSamlConfig(providerId, updatedConfig) .then(function (response) { return new auth_config_1.SAMLConfig(response); }); } return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID)); }; /** * Returns a promise that resolves with the newly created AuthProviderConfig when the new provider configuration is * created. * @param {AuthProviderConfig} config The provider configuration to create. * @return {Promise<AuthProviderConfig>} A promise that resolves with the created provider configuration. */ BaseAuth.prototype.createProviderConfig = function (config) { if (!validator.isNonNullObject(config)) { return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, 'Request is missing "AuthProviderConfig" configuration.')); } if (auth_config_1.OIDCConfig.isProviderId(config.providerId)) { return this.authRequestHandler.createOAuthIdpConfig(config) .then(function (response) { return new auth_config_1.OIDCConfig(response); }); } else if (auth_config_1.SAMLConfig.isProviderId(config.providerId)) { return this.authRequestHandler.createInboundSamlConfig(config) .then(function (response) { return new auth_config_1.SAMLConfig(response); }); } return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID)); }; /** * Verifies the decoded Firebase issued JWT is not revoked or disabled. Returns a promise that * resolves with the decoded claims on success. Rejects the promise with revocation error if revoked * or user disabled. * * @param {DecodedIdToken} decodedIdToken The JWT's decoded claims. * @param {ErrorInfo} revocationErrorInfo The revocation error info to throw on revocation * detection. * @return {Promise<DecodedIdToken>} A promise that will be fulfilled after a successful * verification. */ BaseAuth.prototype.verifyDecodedJWTNotRevokedOrDisabled = function (decodedIdToken, revocationErrorInfo) { // Get tokens valid after time for the corresponding user. return this.getUser(decodedIdToken.sub) .then(function (user) { if (user.disabled) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.USER_DISABLED, 'The user record is disabled.'); } // If no tokens valid after time available, token is not revoked. if (user.tokensValidAfterTime) { // Get the ID token authentication time and convert to milliseconds UTC. var authTimeUtc = decodedIdToken.auth_time * 1000; // Get user tokens valid after time in milliseconds UTC. var validSinceUtc = new Date(user.tokensValidAfterTime).getTime(); // Check if authentication time is older than valid since time. if (authTimeUtc < validSinceUtc) { throw new error_1.FirebaseAuthError(revocationErrorInfo); } } // All checks above passed. Return the decoded token. return decodedIdToken; }); }; return BaseAuth; }()); exports.BaseAuth = BaseAuth; /** * The tenant aware Auth class. */ var TenantAwareAuth = /** @class */ (function (_super) { __extends(TenantAwareAuth, _super); /** * The TenantAwareAuth class constructor. * * @param {object} app The app that created this tenant. * @param tenantId The corresponding tenant ID. * @constructor */ function TenantAwareAuth(app, tenantId) { var _this = _super.call(this, app, new auth_api_request_1.TenantAwareAuthRequestHandler(app, tenantId), createFirebaseTokenGenerator(app, tenantId)) || this; utils.addReadonlyGetter(_this, 'tenantId', tenantId); return _this; } /** * Verifies a JWT auth token. Returns a promise with the tokens claims. Rejects * the promise if the token could not be verified. If checkRevoked is set to true, * verifies if the session corresponding to the ID token was revoked. If the corresponding * user's session was invalidated, an `auth/id-token-revoked` error is thrown. If not specified * the check is not applied. * * @param {string} idToken The JWT to verify. * @param {boolean=} checkRevoked Whether to check if the ID token is revoked. * @return {Promise<DecodedIdToken>} A promise that will be fulfilled after a successful * verification. */ TenantAwareAuth.prototype.verifyIdToken = function (idToken, checkRevoked) { var _this = this; if (checkRevoked === void 0) { checkRevoked = false; } return _super.prototype.verifyIdToken.call(this, idToken, checkRevoked) .then(function (decodedClaims) { // Validate tenant ID. if (decodedClaims.firebase.tenant !== _this.tenantId) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.MISMATCHING_TENANT_ID); } return decodedClaims; }); }; /** * Creates a new Firebase session cookie with the specified options that can be used for * session management (set as a server side session cookie with custom cookie policy). * The session cookie JWT will have the same payload claims as the provided ID token. * * @param {string} idToken The Firebase ID token to exchange for a session cookie. * @param {SessionCookieOptions} sessionCookieOptions The session cookie options which includes * custom session duration. * * @return {Promise<string>} A promise that resolves on success with the created session cookie. */ TenantAwareAuth.prototype.createSessionCookie = function (idToken, sessionCookieOptions) { var _this = this; // Validate arguments before processing. if (!validator.isNonEmptyString(idToken)) { return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ID_TOKEN)); } if (!validator.isNonNullObject(sessionCookieOptions) || !validator.isNumber(sessionCookieOptions.expiresIn)) { return Promise.reject(new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_SESSION_COOKIE_DURATION)); } // This will verify the ID token and then match the tenant ID before creating the session cookie. return this.verifyIdToken(idToken) .then(function () { return _super.prototype.createSessionCookie.call(_this, idToken, sessionCookieOptions); }); }; /** * Verifies a Firebase session cookie. Returns a promise with the tokens claims. Rejects * the promise if the token could not be verified. If checkRevoked is set to true, * verifies if the session corresponding to the session cookie was revoked. If the corresponding * user's session was invalidated, an `auth/session-cookie-revoked` error is thrown. If not * specified the check is not performed. * * @param {string} sessionCookie The session cookie to verify. * @param {boolean=} checkRevoked Whether to check if the session cookie is revoked. * @return {Promise<DecodedIdToken>} A promise that will be fulfilled after a successful * verification. */ TenantAwareAuth.prototype.verifySessionCookie = function (sessionCookie, checkRevoked) { var _this = this; if (checkRevoked === void 0) { checkRevoked = false; } return _super.prototype.verifySessionCookie.call(this, sessionCookie, checkRevoked) .then(function (decodedClaims) { if (decodedClaims.firebase.tenant !== _this.tenantId) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.MISMATCHING_TENANT_ID); } return decodedClaims; }); }; return TenantAwareAuth; }(BaseAuth)); exports.TenantAwareAuth = TenantAwareAuth; /** * Auth service bound to the provided app. * An Auth instance can have multiple tenants. */ var Auth = /** @class */ (function (_super) { __extends(Auth, _super); /** * @param {object} app The app for this Auth service. * @constructor */ function Auth(app) { var _this = _super.call(this, app, new auth_api_request_1.AuthRequestHandler(app)) || this; _this.app_ = app; _this.tenantManager_ = new tenant_manager_1.TenantManager(app); return _this; } Object.defineProperty(Auth.prototype, "app", { /** * Returns the app associated with this Auth instance. * * @return {FirebaseApp} The app associated with this Auth instance. */ get: function () { return this.app_; }, enumerable: false, configurable: true }); /** @return The current Auth instance's tenant manager. */ Auth.prototype.tenantManager = function () { return this.tenantManager_; }; return Auth; }(BaseAuth)); exports.Auth = Auth; function createFirebaseTokenGenerator(app, tenantId) { try { var signer = auth_api_request_1.useEmulator() ? new token_generator_1.EmulatedSigner() : crypto_signer_1.cryptoSignerFromApp(app); return new token_generator_1.FirebaseTokenGenerator(signer, tenantId); } catch (err) { throw token_generator_1.handleCryptoSignerError(err); } }
Back to File Manager