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:
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.
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
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?
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);