Create custom email action handlers

Some user management actions, such as updating a user's email address and resetting a user's password, result in emails being sent to the user. These emails contain links that recipients can open to complete or cancel the user management action. By default, user management emails link to the default action handler, which is a web page hosted at a URL in your project's Firebase Hosting domain.

You can instead create and host a custom email action handler to do custom processing and to integrate the email action handler with your website.

The following user management actions require the user to complete the action using an email action handler:

  • Resetting passwords
  • Revoking email address changes—when users change their accounts' primary email addresses, Firebase sends an email to their old addresses that allow them to undo the change
  • Verifying email addresses

To customize your Firebase project's email action handler, you must create and host a web page that uses the Firebase JavaScript SDK to verify the request's validity and complete the request. Then, you must customize your Firebase project's email templates to link to your custom action handler.

Create the email action handler page

  1. Firebase adds several query parameters to your action handler URL when it generates user management emails. For example:

    These parameters specify the user management task that the user is completing. Your email action handler page must handle the following query parameters:


    The user management action to be completed. Can be one of the following values:

    • resetPassword
    • recoverEmail
    • verifyEmail
    oobCode A one-time code, used to identify and verify a request
    apiKey Your Firebase project's API key, provided for convenience
    continueUrl This is an optional URL that provides a way to pass state back to the app via a URL. This is relevant to password reset and email verification modes. When sending a password reset email or verification email, an ActionCodeSettings object needs to be specified with a continue URL for this to be available. This makes it possible for a user to continue right where they left off after an email action.

    The following example shows how you might handle the query parameters in a browser based handler. (You could also implement the handler as a Node.js application using similar logic.)

    <script src=""></script>
    document.addEventListener('DOMContentLoaded', function() {
      // TODO: Implement getParameterByName()
      // Get the action to complete.
      var mode = getParameterByName('mode');
      // Get the one-time code from the query parameter.
      var actionCode = getParameterByName('oobCode');
      // (Optional) Get the API key from the query parameter.
      var apiKey = getParameterByName('apiKey');
      // (Optional) Get the continue URL from the query parameter if available.
      var continueUrl = getParameterByName('continueUrl');
      // Configure the Firebase SDK.
      // This is the minimum configuration required for the API to be used.
      var config = {
        'apiKey': apiKey  // This key could also be copied from the web
                          // initialization snippet found in the Firebase console.
      var app = firebase.initializeApp(config);
      var auth = app.auth();
      // Handle the user management action.
      switch (mode) {
        case 'resetPassword':
          // Display reset password handler and UI.
          handleResetPassword(auth, actionCode, continueUrl);
        case 'recoverEmail':
          // Display email recovery handler and UI.
          handleRecoverEmail(auth, actionCode);
        case 'verifyEmail':
          // Display email verification handler and UI.
          handleVerifyEmail(auth, actionCode, continueUrl);
          // Error: invalid mode.
    }, false);
  2. Handle password reset requests by first verifying the action code with verifyPasswordResetCode; then get a new password from the user and pass it to confirmPasswordReset. For example:

    function handleResetPassword(auth, actionCode, continueUrl) {
      var accountEmail;
      // Verify the password reset code is valid.
      auth.verifyPasswordResetCode(actionCode).then(function(email) {
        var accountEmail = email;
        // TODO: Show the reset screen with the user's email and ask the user for
        // the new password.
        // Save the new password.
        auth.confirmPasswordReset(actionCode, newPassword).then(function(resp) {
          // Password reset has been confirmed and new password updated.
          // TODO: Display a link back to the app, or sign-in the user directly
          // if the page belongs to the same domain as the app:
          // auth.signInWithEmailAndPassword(accountEmail, newPassword);
          // TODO: If a continue URL is available, display a button which on
          // click redirects the user back to the app via continueUrl with
          // additional state determined from that URL's parameters.
        }).catch(function(error) {
          // Error occurred during confirmation. The code might have expired or the
          // password is too weak.
      }).catch(function(error) {
        // Invalid or expired action code. Ask user to try to reset the password
        // again.
  3. Handle email address change revocations by first verifying the action code with checkActionCode; then restore the user's email address with applyActionCode. For example:

    function handleRecoverEmail(auth, actionCode) {
      var restoredEmail = null;
      // Confirm the action code is valid.
      auth.checkActionCode(actionCode).then(function(info) {
        // Get the restored email address.
        restoredEmail = info['data']['email'];
        // Revert to the old email.
        return auth.applyActionCode(actionCode);
      }).then(function() {
        // Account email reverted to restoredEmail
        // TODO: Display a confirmation message to the user.
        // You might also want to give the user the option to reset their password
        // in case the account was compromised:
        auth.sendPasswordResetEmail(restoredEmail).then(function() {
          // Password reset confirmation sent. Ask user to check their email.
        }).catch(function(error) {
          // Error encountered while sending password reset code.
      }).catch(function(error) {
        // Invalid code.
  4. Handle email address verification by calling applyActionCode. For example:

    function handleVerifyEmail(auth, actionCode, continueUrl) {
      // Try to apply the email verification code.
      auth.applyActionCode(actionCode).then(function(resp) {
        // Email address has been verified.
        // TODO: Display a confirmation message to the user.
        // You could also provide the user with a link back to the app.
        // TODO: If a continue URL is available, display a button which on
        // click redirects the user back to the app via continueUrl with
        // additional state determined from that URL's parameters.
      }).catch(function(error) {
        // Code is invalid or expired. Ask the user to verify their email address
        // again.
  5. Host the page somewhere, such as by using Firebase Hosting.

Next, you must configure your Firebase project to link to your custom email action handler in its user management emails.

To configure your Firebase project to use your custom email action handler:

  1. Open your project in the Firebase console.
  2. Go to the Email Templates page in the Auth section.
  3. In any of the Email Types entries, click the pencil icon to edit the email template.
  4. Click customize action URL, and specify the URL to your custom email action handler.

After you save the URL, it will be used by all of your Firebase project's email templates.

Send feedback about...

Need help? Visit our support page.