5

I thought it would be a good idea to combine a Reactjs frontend with data stored in Firebase, leveraging all the supporting tools it offers, especially authentication.

I've set up a very simple basic app where, if you're not logged in, it takes you to a login screen, and if you are logged in, it shows you your email and ID, all very basic. For the login, I wanted to use Firebase UI, an interface provided by Google that allows you to log in with email and password, as well as with Google and many other providers. However, I only need Email/password and Google.

So, with the help of an online tutorial I put it all together, and it appears to be running without errors. However, I'm facing two practical issues:

  • When I use email/password to log in, I enter my email, it prompts me to create an account by entering a password, I do that and get logged in. I also receive a verification email, which works. The problem is that if I log out and then try to log back in with the same credentials, it essentially prompts me to create a new user by entering a new password. If I try to proceed, it says the email already exists, and I can reset the password.

  • When using the Google Account option, the popup mode works fine. However, the redirect mode takes me to the Google login, asks for permissions, returns to the app, but essentially doesn't trigger any callback with the user login (unlike what happens in the popup version). Interestingly, the user is still created in Firebase, but I can't log in to the React app.

I attach the three main components (without expecting anyone to go through them necessarily):

App Component: App.js

import React, { useEffect, useState } from 'react';
import logo from './logo.svg';
import './App.css';
import Login from './Login';
import {Authenticated} from './Authenticated';
import {  firebaseConfig } from './firebase_config.js'; // i don't attach the file, there are only API keys of firebase account
import {initializeApp } from 'firebase/app';

import * as firebaseui from "firebaseui/dist/npm__it"; // it's like the original one but only done with italian strings

import { getAuth, setPersistence, browserLocalPersistence, onAuthStateChanged  } from "firebase/auth";
import {getFirestore} from 'firebase/firestore'; 
import {BrowserRouter, Route, Routes, } from 'react-router-dom'
const appFirebase=initializeApp(firebaseConfig);
const auth=getAuth(appFirebase);
const ui=new firebaseui.auth.AuthUI(auth);
function App() {
  
  const [user, setUser]= useState();
  useEffect(()=> {
    
    onAuthStateChanged(auth, (userFound)  =>{
      console.log("Auth changed",auth);
      if (userFound) {
        setUser({email: userFound.email, id: userFound.uid});

      }
      else setUser(null);
      
    });
  });
  
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        
        <BrowserRouter>
        <Routes>
            <Route path="/login" element={<Login auth={auth} user={user} ui={ui}/>}></Route>          
            <Route path="/" element={<Authenticated user={user} />}> </Route>
        </Routes>
        </BrowserRouter>
        {user && <div><button onClick={() => { auth.signOut()}} >Logout</button></div>}
      </header>
    </div>
  );
}

export default App;
export { auth };

Login Component: Login.js

import React, { useEffect, useState } from 'react';
import { EmailAuthProvider, GoogleAuthProvider, sendEmailVerification    } from "firebase/auth";
import 'firebaseui/dist/firebaseui.css'
import {Navigate} from 'react-router-dom';


const  Login = (props) => {
  

  useEffect(() => {
          
      props.ui.start('#firebaseui-auth-container', {
      callbacks: {
        
          signInFailure: function (error) {
            console.log(error);
          },
          signInSuccessWithAuthResult: function(authResult, redirectUrl) {    
            console.log("signed id",authResult);
            props.auth.languageCode = 'it';

            if (authResult.additionalUserInfo.isNewUser && authResult.additionalUserInfo.providerId==="password")
            {
                console.log("new signin");
                sendEmailVerification(authResult.user);
            }
            return true;
          },
        
      },
      signInSuccessUrl: '/login',
      
      signInOptions: [
        {
          provider: EmailAuthProvider.PROVIDER_ID,
          requireDisplayName: false
        },    
        GoogleAuthProvider.PROVIDER_ID,
      ],
      tosUrl: '<your-tos-url>',
  
      privacyPolicyUrl: '<your-privacy-policy-url>'
    });
  }, [props.auth,props.ui]);
  
  return (
    <>{props.user && (
      <Navigate to="/" replace={true} />
    )}<div>
      <h1>Accesso / Registrazione</h1>
      <div id="firebaseui-auth-container"></div>
    </div></>
  );
}

export default Login;

Authenticated Component: Authenticated.js

import React from "react";

import { Navigate} from 'react-router-dom'

export const Authenticated = (props) => {
    const user=props.user;
    return <>{!user ? 
        <Navigate to="/login" replace={true} />
      :<div>Authenticated
        <div><span>Email</span>:<span>{user.email}</span></div>
        <div><span>Uid</span>:<span>{user.id}</span></div>

    </div>}</>
}

I'm using the following versions:

  • firebase 10.4.0
  • firebaseui 6.1.0

These are essentially the versions that Google recommends installing from here: https://firebase.google.com/docs/auth/web/firebaseui?hl=it

1 Answer 1

3

This problem is related to a change in firebase authentication (added email enumeration protection as default for all new projects created after September 15, 2023). Firebase UI tries to fetch all available sign-in methods for an email address but because of the change, only an empty array is returned.

There are two options to solve that problem:

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.