# How to Reset Password in Firebase Auth

- Tool: Firebase
- Difficulty: Intermediate
- Time required: 10-15 min
- Compatibility: Firebase JS SDK v9+, Firebase Auth, all plans
- Last updated: March 2026

## TL;DR

To reset a password in Firebase Auth, call sendPasswordResetEmail() with the user's email address. Firebase sends a password reset link to the email. You can customize the email template in the Firebase Console under Authentication > Templates, and configure actionCodeSettings to redirect users back to your app after resetting. Always handle errors like user-not-found and too-many-requests gracefully.

## Implementing Password Reset in Firebase Auth

Firebase Auth provides a built-in password reset flow for email/password accounts. This tutorial walks you through sending the reset email, customizing the email template and redirect behavior, handling the reset action link in your app, and confirming the password change. You will also learn how to handle edge cases like invalid emails, expired links, and rate limiting.

## Before you start

- A Firebase project with Authentication enabled
- Email/Password sign-in method enabled in Firebase Console > Authentication > Sign-in method
- Firebase JS SDK v9+ installed in your project
- A working sign-in flow so users have existing accounts to reset

## Step-by-step guide

### 1. Send a password reset email

Use the sendPasswordResetEmail() function from the Firebase Auth SDK. Pass the auth instance and the user's email address. Firebase sends a pre-built email with a password reset link. The function is fire-and-forget from the user's perspective, but you should handle errors to provide good UX. For security, do not reveal whether the email exists in your system to prevent email enumeration.

```
import { getAuth, sendPasswordResetEmail } from 'firebase/auth';

const auth = getAuth();

async function handlePasswordReset(email: string) {
  try {
    await sendPasswordResetEmail(auth, email);
    // Always show success message even if email doesn't exist
    // This prevents email enumeration attacks
    console.log('Password reset email sent');
  } catch (error: any) {
    switch (error.code) {
      case 'auth/invalid-email':
        console.error('Invalid email address format');
        break;
      case 'auth/too-many-requests':
        console.error('Too many attempts. Please try again later.');
        break;
      default:
        console.error('Error sending reset email:', error.message);
    }
  }
}
```

**Expected result:** Firebase sends a password reset email to the specified address if the account exists.

### 2. Configure actionCodeSettings for redirect

Pass an actionCodeSettings object to sendPasswordResetEmail() to control where users are redirected after clicking the reset link. The url property specifies your app's URL where the password reset will be completed. This is especially important for single-page applications and mobile apps. Add the redirect URL to your authorized domains in Firebase Console > Authentication > Settings > Authorized domains.

```
import { getAuth, sendPasswordResetEmail, ActionCodeSettings } from 'firebase/auth';

const auth = getAuth();

const actionCodeSettings: ActionCodeSettings = {
  url: 'https://your-app.com/auth/reset-complete',
  handleCodeInApp: true
};

async function sendReset(email: string) {
  try {
    await sendPasswordResetEmail(auth, email, actionCodeSettings);
    console.log('Reset email sent with custom redirect');
  } catch (error: any) {
    console.error('Error:', error.message);
  }
}
```

**Expected result:** The password reset email links back to your specified URL with an oobCode query parameter.

### 3. Customize the email template

Firebase provides a default password reset email template that you can customize. In the Firebase Console, go to Authentication > Templates > Password reset. You can edit the subject line, sender name, message body, and action URL. The template supports placeholders like %APP_NAME%, %LINK%, and %EMAIL%. For fully custom emails, use Firebase Admin SDK server-side to generate the reset link and send it through your own email provider.

```
// Server-side: Generate a custom reset link with Admin SDK
import { getAuth } from 'firebase-admin/auth';

async function generateCustomResetLink(email: string) {
  const auth = getAuth();
  const actionCodeSettings = {
    url: 'https://your-app.com/auth/reset-complete'
  };

  const link = await auth.generatePasswordResetLink(
    email,
    actionCodeSettings
  );

  // Send the link via your own email service
  // await sendCustomEmail(email, link);
  return link;
}
```

**Expected result:** Users receive a branded password reset email with your custom subject, message, and redirect URL.

### 4. Handle the reset action link in your app

When users click the password reset link, they are redirected to your app with an oobCode (out-of-band code) in the URL query parameters. Extract this code, verify it with verifyPasswordResetCode() to get the associated email, then prompt the user for a new password. Finally, call confirmPasswordReset() with the code and the new password to complete the reset.

```
import {
  getAuth,
  verifyPasswordResetCode,
  confirmPasswordReset
} from 'firebase/auth';

const auth = getAuth();

async function handleResetAction(oobCode: string, newPassword: string) {
  try {
    // Verify the code is valid and get the associated email
    const email = await verifyPasswordResetCode(auth, oobCode);
    console.log('Reset code valid for:', email);

    // Confirm the password reset
    await confirmPasswordReset(auth, oobCode, newPassword);
    console.log('Password has been reset successfully');

    // Optionally sign the user in automatically
    // await signInWithEmailAndPassword(auth, email, newPassword);
  } catch (error: any) {
    switch (error.code) {
      case 'auth/expired-action-code':
        console.error('Reset link has expired. Please request a new one.');
        break;
      case 'auth/invalid-action-code':
        console.error('Reset link is invalid or has already been used.');
        break;
      case 'auth/weak-password':
        console.error('Password is too weak. Use at least 6 characters.');
        break;
      default:
        console.error('Error resetting password:', error.message);
    }
  }
}
```

**Expected result:** The user's password is changed to the new password and they can sign in with it immediately.

### 5. Build a password reset form component

Create a complete React component that handles both the reset request and the reset confirmation. The component checks the URL for an oobCode parameter to determine which view to show: the email input form for requesting a reset, or the new password form for completing the reset.

```
import { useState, useEffect } from 'react';
import {
  getAuth,
  sendPasswordResetEmail,
  verifyPasswordResetCode,
  confirmPasswordReset
} from 'firebase/auth';

function PasswordReset() {
  const auth = getAuth();
  const [email, setEmail] = useState('');
  const [newPassword, setNewPassword] = useState('');
  const [message, setMessage] = useState('');
  const [oobCode, setOobCode] = useState<string | null>(null);

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const code = params.get('oobCode');
    if (code) setOobCode(code);
  }, []);

  const handleSendReset = async () => {
    try {
      await sendPasswordResetEmail(auth, email);
      setMessage('Check your email for a reset link.');
    } catch {
      setMessage('Something went wrong. Try again.');
    }
  };

  const handleConfirmReset = async () => {
    if (!oobCode) return;
    try {
      await confirmPasswordReset(auth, oobCode, newPassword);
      setMessage('Password reset! You can now sign in.');
    } catch {
      setMessage('Link expired or invalid. Request a new one.');
    }
  };

  // Render either the request form or the confirm form
}
```

**Expected result:** Users can request a password reset and complete it within your application without leaving to an external page.

## Complete code example

File: `password-reset.ts`

```typescript
import {
  getAuth,
  sendPasswordResetEmail,
  verifyPasswordResetCode,
  confirmPasswordReset,
  signInWithEmailAndPassword,
  ActionCodeSettings
} from 'firebase/auth';
import { initializeApp } from 'firebase/app';

const app = initializeApp({
  apiKey: 'YOUR_API_KEY',
  authDomain: 'YOUR_PROJECT.firebaseapp.com',
  projectId: 'YOUR_PROJECT_ID'
});

const auth = getAuth(app);

const actionCodeSettings: ActionCodeSettings = {
  url: 'https://your-app.com/auth/reset-complete',
  handleCodeInApp: true
};

export async function requestPasswordReset(email: string): Promise<string> {
  try {
    await sendPasswordResetEmail(auth, email, actionCodeSettings);
    return 'If an account exists with this email, a reset link has been sent.';
  } catch (error: any) {
    if (error.code === 'auth/too-many-requests') {
      return 'Too many attempts. Please wait before trying again.';
    }
    if (error.code === 'auth/invalid-email') {
      return 'Please enter a valid email address.';
    }
    return 'An error occurred. Please try again.';
  }
}

export async function completePasswordReset(
  oobCode: string,
  newPassword: string
): Promise<{ success: boolean; message: string; email?: string }> {
  try {
    const email = await verifyPasswordResetCode(auth, oobCode);
    await confirmPasswordReset(auth, oobCode, newPassword);

    // Auto sign-in after reset
    await signInWithEmailAndPassword(auth, email, newPassword);

    return {
      success: true,
      message: 'Password reset successfully. You are now signed in.',
      email
    };
  } catch (error: any) {
    const messages: Record<string, string> = {
      'auth/expired-action-code': 'This reset link has expired. Request a new one.',
      'auth/invalid-action-code': 'This reset link is invalid or already used.',
      'auth/weak-password': 'Password must be at least 6 characters.'
    };
    return {
      success: false,
      message: messages[error.code] || 'Failed to reset password.'
    };
  }
}
```

## Common mistakes

- **Revealing whether an email exists by showing different messages for existing vs non-existing accounts** — undefined Fix: Always show a generic success message like 'If an account exists, a reset link has been sent.' This prevents email enumeration attacks where attackers probe for valid email addresses.
- **Not adding the redirect URL to the authorized domains list in Firebase Console** — undefined Fix: Go to Firebase Console > Authentication > Settings > Authorized domains and add the domain used in your actionCodeSettings URL. Without this, users see a 'domain not authorized' error.
- **Assuming the oobCode in the URL never expires** — undefined Fix: Password reset codes expire after 1 hour and can only be used once. Always handle the auth/expired-action-code and auth/invalid-action-code errors and prompt users to request a new reset email.

## Best practices

- Show a generic success message regardless of whether the email exists to prevent enumeration attacks
- Use actionCodeSettings to redirect users back to your app after clicking the reset link
- Customize the email template in Firebase Console to match your brand
- Validate the new password on the client side before calling confirmPasswordReset()
- Handle all error codes including expired-action-code, invalid-action-code, and weak-password
- Consider auto-signing the user in after a successful password reset for better UX
- Add rate limiting UI feedback to inform users about the 5 emails per hour limit
- Log password reset events for security auditing purposes

## Frequently asked questions

### How long does a Firebase password reset link last?

Password reset links expire after 1 hour. If a user clicks an expired link, they will see an error. Your app should handle the auth/expired-action-code error and prompt the user to request a new reset email.

### Can I customize the password reset email content?

Yes. Go to Firebase Console > Authentication > Templates > Password reset to edit the subject, sender name, and body text. For fully custom emails with your own design, use the Admin SDK's generatePasswordResetLink() to get the link and send it via your own email service.

### What happens if the user's email doesn't exist in Firebase Auth?

By default, sendPasswordResetEmail() throws an auth/user-not-found error. However, if you enable Email enumeration protection in Firebase Console > Authentication > Settings, the function succeeds silently. Either way, show a generic success message to prevent email enumeration.

### Can I set minimum password requirements for the new password?

Firebase enforces a minimum password length of 6 characters. For stricter requirements, validate the password on the client side before calling confirmPasswordReset(). Firebase does not have built-in complexity rules, so implement those checks in your app.

### Does password reset work with OAuth accounts (Google, GitHub)?

No. Password reset only applies to email/password accounts. If a user signed up with Google or GitHub OAuth, they do not have a Firebase password to reset. Their authentication is managed by the OAuth provider.

### Can I send password reset emails programmatically from the server?

Yes. Use the Firebase Admin SDK's getAuth().generatePasswordResetLink(email, actionCodeSettings) to generate the reset link server-side, then send it via your own email service like SendGrid or Mailgun for full control over the email design.

### Can RapidDev help build a custom password reset flow?

Yes. RapidDev can implement a fully customized password reset experience including branded email templates, custom redirect flows, server-side link generation, and integration with your existing email service provider.

---

Source: https://www.rapidevelopers.com/firebase-tutorial/how-to-reset-password-in-firebase-auth
© RapidDev — https://www.rapidevelopers.com/firebase-tutorial/how-to-reset-password-in-firebase-auth
