Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sendPasswordResetEmail is not throwing error if user does not exist #7651

Closed
BilalAtique opened this issue Sep 26, 2023 · 25 comments
Closed

Comments

@BilalAtique
Copy link

Operating System

Window 10

Browser Version

Chrome Version 116.0.5845.188 (Official Build) (64-bit)

Firebase SDK Version

10.4.0

Firebase SDK Product:

Auth

Describe your project's tooling

React app with Vite

Describe the problem

I am trying to set the forgotten password in the React app. For this, I am using sendPasswordResetEmail, and it is working great. The problem is it is not throwing an error when an email that does not exist is passed.

Steps and code to reproduce issue

Here's the code:

async function sendResetPasswordEmail(email: string) {
  try {
    await sendPasswordResetEmail(auth, email);
    return { error : null};
  } catch (error: any) {
    return { error}
  }
}

auth is imported from config file.

@BilalAtique BilalAtique added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Sep 26, 2023
@jbalidiong jbalidiong added needs-attention and removed new A new issue that hasn't be categoirzed as question, bug or feature request labels Sep 27, 2023
@jbalidiong
Copy link
Contributor

Hi @BilalAtique, thanks for reaching out to us. I tried replicating the issue but I was able to see an error thrown when an email is not existing. Using the code snippet above, I've added a console log before the return of error to see if it is throwing an error. The message returned:

FirebaseError: Firebase: Error (auth/user-not-found).

Here is the edited code snippet:

try {
      await sendPasswordResetEmail(auth, email);
      return { error : null};
    } catch (error: any) {
      console.log(error)
      return error
}

Could you try checking if you will see the error when using the console.log(). You can also use throw error.message to signal an error or exception.

@BilalAtique
Copy link
Author

BilalAtique commented Sep 27, 2023

Hi @jbalidiong, Not working for me. Is it because the user is not logged in when I am calling this function?

@hsubox76
Copy link
Contributor

That shouldn't have anything to do with it. Are you seeing anything in the console at all? Does your function return {error: null}? I'm running:

try {
  await sendPasswordResetEmail(auth, 'fff@abc.com');
  console.log('sent');
} catch (e) {
  console.log(e);
}

and getting

FirebaseError: Firebase: Error (auth/user-not-found).
    at createErrorInternal (assert.ts:136:55)
    at _fail (assert.ts:65:9)
    at _performFetchWithErrorHandling (index.ts:196:9)
    at async sendPasswordResetEmail (email_and_password.ts:132:5)
    at async app5.js:21:3

in the console. Can you try creating a blank test app that has only this code and nothing else (plus the imports and config needed)? Just to rule out that it's not caused by any of the other code around it?

@BilalAtique
Copy link
Author

Hi @hsubox76 . This is the request payload:

{
    "requestType": "PASSWORD_RESET",
    "email": "abc@gmail.com",
    "clientType": "CLIENT_TYPE_WEB"
}

and this is the response I am getting:

{
  "kind": "identitytoolkit#GetOobConfirmationCodeResponse",
  "email": "abc@gmail.com"
}

As you can see from the request and response, this is not a possibility because the request payload is as expected and the server response does not contain any error. But still, I tried with no success.
Here's my config file:

import { getApps, initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";

// Replaced the actual firebaseConfig with dummy text
const firebaseConfig = {
  apiKey: "API_KEY",
  authDomain: "AUTH_DOMAIN",
  projectId: "PROJECT_ID",
  storageBucket: "STORAGE_BUCKET",
  messagingSenderId: "MESSAGING_SENDER_ID",
  appId: "APP_ID",
  measurementId: "MEASUREMENT_ID"
};

const firebaseApp =
  getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];

const auth = getAuth(firebaseApp);
const db = getFirestore(firebaseApp);

export default firebaseApp;

export { db, auth };

and this is the file containing sendPasswordResetEmail:

import { sendPasswordResetEmail } from "firebase/auth";
import { auth } from "../config/firebase.config";

async function sendResetPasswordEmail(email: string) {
  try {
    await sendPasswordResetEmail(auth, email);
    console.log("success")
    return { error : null};
  } catch (error: any) {
    console.log(error)
    return { error}
  }
}

export default sendResetPasswordEmail

@jbalidiong
Copy link
Contributor

@BilalAtique, We have the same request payload but have a different response. I am getting:

{
  "error": {
    "code": 400,
    "message": "EMAIL_NOT_FOUND",
    "errors": [
      {
        "message": "EMAIL_NOT_FOUND",
        "domain": "global",
        "reason": "invalid"
      }
    ]
  }
}

The response you are getting is for the successful one. (email is existing on the Firebase project). Can you make sure that email in the request is not used by any users as Identifier in the Firebase Authentication. You can also check the console tab to see if you're getting any logs at all.

@BilalAtique
Copy link
Author

@jbalidiong No account with that email exists. Also, I am receiving "success" in the console coming from the above-mentioned function.

@jbalidiong
Copy link
Contributor

That shouldn't happen, I still couldn't replicate the behavior you are encountering. Let me try it using your given code snippet and a blank project.

@lightlitebug
Copy link

I am developing a flutter app but facing the same problem. In case of a non-existent email, sendPasswordResetEmail does not throw an error.

@jbalidiong
Copy link
Contributor

Apologies for the delay response. I still cannot replicate the error you're encountering. Can you share a minimal, but complete sample of a project that I can run locally. I'll also check this with our Auth team or bring someone here that can provide more context about it.

@lightlitebug
Copy link

Here is my complete source code.
https://github.com/lightlitebug/fb_auth_riverpod

One more question. Does firebase_auth team enable 'email enumeration protection' by default?
The error message I got from firebase is different from the previous one.

When I enter wrong password
Current: INVALID_LOGIN_CREDENTIALS
Past: wrong-password

@mshahzaib101vaionex
Copy link

I am also facing this issue

@mshahzaib101
Copy link

I am also facing this isssue in my new Free tier project (Spark Plan).
Is Spark Plan is the reason? because it is working fine on other plans projects.
Is Email enumeration is enabled by default in new projects?

@BilalAtique
Copy link
Author

@mshahzaib101 Spark plan is surely not the reason as I am facing it on the Blaze plan

@jbalidiong
Copy link
Contributor

Hi @BilalAtique, upon checking with our Auth team. This seems to be coming from the backend. In that case, you may want to file a ticket via Firebase support channel and provide the HAR file and check the state in the backend.

@jbalidiong
Copy link
Contributor

@lightlitebug, the issue regarding INVALID_LOGIN_CREDENTIALS is not related to the original post. For newly create project, the email enumeration protection is enable by default and providing an incorrect password will let your user receive the said error message. You can disable it in the console to revert to the previous error message. You can follow our documentation for guidance.

@lightlitebug
Copy link

Thanks for the confirmation.
I mentioned INVALID_LOGIN_CREDENTIALS separately because I was wondering if it might be related to sendPasswordResetEmail.
The INVALID_LOGIN_CREDENTIALS error response doesn't tell us anything about the user, which means a hacker can't get any information about whether the email is registered or whether the password is correct.
However, if sendPasswordResetEmail gives a user-not-found error, it tells the hacker that the email doesn't exist in the system.
In this case, sendPasswordResetEmail tells us more about the user than it does about the sign in.
So my guess is that the firebase team changed the result of sendPasswordResetEmail to unconditional success in order to be consistent with security, i.e., to not give away any information about the user's credentials.

@jbalidiong
Copy link
Contributor

Hello, everyone. Upon checking the "email enumeration protection" document, if this feature was enabled according to our docs:

Removes error responses for email verification flows, such as those initiated by calling the sendOobCode REST API with request types VERIFY_AND_CHANGE_EMAIL or PASSWORD_RESET, and when calling the verifyBeforeUpdateEmail or sendPasswordResetEmail client SDK methods on all platforms.

I was able to verify this by the suggestion of @lightlitebug. The reason why we aren't able to replicate this is because the project used for debugging this was created before Sept. 15. If you created your project on or after September 15, 2023, email enumeration protection is enabled by default. I tried enabling and disabling the feature in a new project and confirmed the reported behavior. I've communicated with our engineers regarding this issue, I’ll update this thread if I have any information to share.

@MauriceBonnesDev
Copy link

Hey, I am also facing this issue in a flutter application. Thanks for the responses. So we just have to wait, I guess? 👀

@prameshj
Copy link
Contributor

prameshj commented Oct 6, 2023

This behavior change is due to the Email Enumeration protection feature that is enabled by default on new projects (created on or after Sep 15). There is an option to disable the feature, in case your app relies on this functionality. We recommend not relying on this functionality in the long term, since it can pose a security risk.

@lohnsonok
Copy link

This behavior change is due to the Email Enumeration protection feature that is enabled by default on new projects (created on or after Sep 15). There is an option to disable the feature, in case your app relies on this functionality. We recommend not relying on this functionality in the long term, since it can pose a security risk.

it worked

@k4ploc
Copy link

k4ploc commented Dec 27, 2023

This behavior change is due to the Email Enumeration protection feature that is enabled by default on new projects (created on or after Sep 15). There is an option to disable the feature, in case your app relies on this functionality. We recommend not relying on this functionality in the long term, since it can pose a security risk.

thank you, yeah it is indeed necessary to disable this function, but any alternative to check that it is a registered email, because if I use the fetchSignInMethodsForEmail method to check for mail, it also returns empty [ ].?

@renkelvin
Copy link
Contributor

@JuanLongines There isn't a comparable substitute since it's susceptible to email enumeration attacks.

@Luna0214
Copy link

@BilalAtique @jbalidiong I am facing exact same problem. sendPasswordResetEmail() does not throw an exception: Firebase: Error (auth/user-not-found). Did you find any solution to make it throw the exception?

@jbalidiong
Copy link
Contributor

This behavior change is due to the Email Enumeration protection feature that is enabled by default on new projects (created on or after Sep 15). There is an option to disable the feature, in case your app relies on this functionality. We recommend not relying on this functionality in the long term, since it can pose a security risk.

Hi @Luna0214, based from the workaround that our engineer provided. You can disable the feature if you are relying on this functionality.

@jbalidiong
Copy link
Contributor

It looks like the initial issue was already solved. I'll be closing this issue now. If you encounter another issue, feel free to create a new one.

@firebase firebase locked and limited conversation to collaborators Feb 25, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests