/*! firebase-admin v9.10.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 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.
     */
    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.verifyDecodedJWTNotRevoked(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 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.
     */
    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 token was revoked.
            if (checkRevoked || isEmulator) {
                return _this.verifyDecodedJWTNotRevoked(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. Returns a promise that resolves
     * with the decoded claims on success. Rejects the promise with revocation error if revoked.
     *
     * @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.verifyDecodedJWTNotRevoked = function (decodedIdToken, revocationErrorInfo) {
        // Get tokens valid after time for the corresponding user.
        return this.getUser(decodedIdToken.sub)
            .then(function (user) {
            // 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);
    }
}
