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