firebasegoogle-cloud-platformfirebase-authenticationgoogle-identity

Invalid Firebase Email/Password Auth Handler (missing providerId)


After using createUserWithEmailAndPassword from firebase/auth, Firebase sends a verification email to the user. The verification link successfully verifies the email, but instead of redirecting back to my app, I am redirected to the following URLs:

Local with the emulator:

http://localhost:9099/emulator/auth/handler?apiKey=fake-api-key&appName=%5BDEFAULT%5D&authType=reauthViaRedirect&redirectUrl=http%3A%2F%2Flocalhost%3A3000%2Fapp&v=9.21.0&eventId=VBnwo5RI30cI7UvoCwfBQfZXNmmm%3A%3A%3A7630387099

with the following error:

{ "authEmulator": { "error": "missing apiKey or providerId query parameters" } }

For local emulation on the backend, I am calling admin.auth().generateEmailVerificationLink(email, { url: "http://localhost:3000/app"}) to generate an email verification link. This link looks like:

http://127.0.0.1:9099/emulator/action?mode=verifyEmail&lang=en&oobCode=XXX&apiKey=fake-api-key&continueUrl=http%3A%2F%2Flocalhost%3A3000%2Fapp

It leads to a verification success, then redirects automatically to localhost:3000/app, however it doesn't stay there long as that is when I am redirected to the error-state URL shown above.

And production:

https://example.com/__/auth/handler?apiKey=XXX&appName=%5BDEFAULT%5D&authType=reauthViaRedirect&redirectUrl=https%3A%2F%2Fexample.com%2Fapp%2Fregister%2Fverify-email&v=9.21.0&eventId=TIaOYg0R5QdkPxrXuZl5IClNFd52%3A%3A%3A9624473175

with the following error:

The requested action is invalid.
...
Request is missing required data

For production, I am letting Firebase handle the verification email by calling sendEmailVerification(auth.currentUser, { url: window.location.href }) on the front end. I do NOT use a custom email action handler [1] [2]. Instead, in the Firebase console, I set the action URL to https://example.com/__/auth/action with the proper domain verification [3], but I've also tried it by resetting it to the default, and it causes the same behavior. This is the link it generates:

https://example.com/__/auth/action?mode=verifyEmail&oobCode=XXX&apiKey=XXX&continueUrl=https%3A%2F%example.com%2Fapp%2Fregister%2Fverify-email&lang=en

Additional Details

Note that if I simply navigate a second time to (local) localhost:3000/app or (prod) https://example.com/app, it doesn't redirect me incorrectly and everything works fine.

Curiously, if I add in &providerId=password to the query parameters, it works just fine; however, I have no idea what is generating this URL nor why it is not including the providerId (if that is even the root of the problem). Any help in understanding what I'm doing wrong?


Solution

  • Answer was resolved here: https://github.com/firebase/firebase-js-sdk/issues/7303

    TL:DR; The issue was calling reauthenticateWithRedirect while attempting to pass the password providerId to the call without providing a credential.

    As soon as the email is verified, the firebase user itself is not authenticated (just the email verified). I thought using reauthenticateWithRedirect would resolve this (and it does, but I need to give it the credential). It looks like for email/password the expectation is supposed to be that the user is forced to sign back in rather than being automatically reauthenticated?

    There doesn't appear to be any way to reauthenticate the password method without having them reenter their credentials. The best bet is to call reauthenticateWithCredential after extracting the email from the firebase user and asking the user to re-enter the password.

    Here's an example:

    const email = auth.currentUser.email;
    const password = ???; // get from user-provided input
    const credential = EmailAuthProvider.credential(email, password);
    await reauthenticateWithCredential(auth.currentUser, credential);
    

    Source