Sometimes we want to implement authentication for multiple reasons and we don't want to create an API just for the authentication or maybe we are not backend developers. That's why Firebase provides authentication backend services easy to use. It supports authentication using passwords, phone numbers, popular social networks like Google, Facebook and Twitter, and more.
First of all, we have to have a Google account (Gmail account). If you don't have an account, create it before starting.
We have to go to their website, log in if we are not logged in, and click on
Get Started
.And after that, we click on
Add project
.We have to put a name for our project. For this tutorial I am going to name it react-authentication.
Click on
continue
.For this project I am going to disable Google Analytics. It doesn't affect in anything, so you could enable it if you want.
Finally we click on
Create project
.When we see this image, it means that we are ready to go.
Click on
Continue
.Firebase is not only for web applications, it is also for mobil devices and unity games. But in this case we are going to create a React web app.
Click on the marked icon.
Now, we have to put a nickname for our application. It doesn't matter which nickname we put it, after all, we are the only ones that are going to see it. I recommend you put a nickname related to the project.
Click on
Register app
.After a few seconds Firebase is going to give us a code that we will then have to put in our projects.
Now we have to go to the
authentication
area.Click on
Set up sign-in method
.We can see that we have a lot of types of authentication but in this tutorial we are just cover the
Email/Password
method.Before clicking the
Email/Password
method, we can see below that we have the authorized domains. By default there are 3, but you can add more domains.Now we are going to enable just the first option. The second option is like it says. When we try to login, google is going to send us a link to our email to login.
And that's it. We are done with the Firebase configuration.
First of all we have to install the dependencies that are going to help us:
npm i --save firebase reactfire@next
To keep everything in order we are going to create a file named
firebaseConfig.js
in our src
folder. Inside of the firebaseConfig,js file, we add it the json code and export it.// src/firebaseConfig.js
const firebaseConfig = {
apiKey: "AIzaSyBSo7NZouVtr-G36eLbFGjXv_IN7cBBn30",
authDomain: "react-authentication-2c83f.firebaseapp.com",
databaseURL: "https://react-authentication-2c83f.firebaseio.com",
projectId: "react-authentication-2c83f",
storageBucket: "react-authentication-2c83f.appspot.com",
messagingSenderId: "194995380667",
appId: "1:194995380667:web:5e5dd9db459ab8a21da49e"
}
export default firebaseConfig;
Now, to Firebase work, we have to wrap the entire app with FirebaseAppProvider and this provider needs to receive the firebase configuration that we created before.
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom';
import { FirebaseAppProvider } from 'reactfire';
import firebaseConfig from './firebaseConfig';
import App from './App';
import './index.css';
ReactDOM.render(
<FirebaseAppProvider firebaseConfig={firebaseConfig}>
<Suspense fallback={<h3>Loading...</h3>}>
<React.StrictMode>
<App />
</React.StrictMode>
</Suspense>
</FirebaseAppProvider>,
document.getElementById('root')
);
If you don't know what is suspense component from React, you can check it here.
To see if everything is working well, we could import
useFirebaseApp
and do a console.log()
to see in our web console what is going on. We have to add the userFirebaseApp
in our App.js
fileimport React from 'react';
import './App.css';
import { useFirebaseApp } from 'reactfire';
function App() {
const firebase = useFirebaseApp();
console.log(firebase);
return (
// Some code
);
}
export default App;
We can delete the console.log() that we created before so we can continue with the tutorial.
First, let's create a
Sign Up
component.import React, { useState } from 'react';
import './Signup.css';
const Signup = () => {
// User State
const [user, setUser] = useState({
nickname: '',
email: '',
password: '',
error: '',
});
// onChange function
const handleChange = e => {
setUser({
...user,
[e.target.name]: e.target.value,
error: '',
})
};
// Submit function (Create account)
const handleSubmit = e => {
e.preventDefault();
// Sign up code here.
}
return (
<>
<h1>Sign up</h1>
<form onSubmit={handleSubmit}>
<input type="text" placeholder="Nickname" name="nickname" onChange={handleChange}/><br />
<input type="text" placeholder="Email" name="email" onChange={handleChange}/><br />
<input type="password" placeholder="Password" name="password" onChange={handleChange}/><br />
<button type="submit">Sign Up</button>
</form>
{user.error && <h4>{user.error}</h4>}
</>
)
};
export default Signup;
Lets explain:
handleChange
function that updated the state when the user does a change in the inputs. Also reset the error message to hide it.handleSubmit
function is where we are going to send the information to Firebase.nickname
input is optional, we are going to see why in the next steps.And this is the result. I added minor styling so your form could look diferent.
Now we are going to finish the
handleSubmit
function.import React, { useState } from 'react';
import { useFirebaseApp } from 'reactfire';
import 'firebase/auth'
import './Signup.css';
const Signup = () => {
// Previous code...
// Import firebase
const firebase = useFirebaseApp();
// Submit function (Create account)
const handleSubmit = async(e) => {
e.preventDefault();
// Sign up code here.
await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
.then(result => {
// Update the nickname
result.user.updateProfile({
displayName: user.nickname,
})
}).catch(error => {
// Update the error
console.log(error);
setUser({
...user,
error: error.message,
})
})
}
return (
// Previous code...
)
};
export default Signup;
useFirebaseApp
and firebase/auth
, so we can start to create the user.useFirebaseApp
to firebase
const.firebase.auth().createUserWithEmailAndPassword()
will recive just an email and a password, like it says in the name. That's why making a nickname
is optional.user.updateProfile()
. This receives an object with 2 optional parameters: displayName
to update the username and the photoURL
to add a picture avatar. In this tutorial we are just using displayName
.catch
part we just update the error message.With this code we could say that is done, and yes it is, we got what we wanted, but we can improve it.
Right now when we Sign up, we don't know if the email is a valid or not, also Firebase automatically logged us in and maybe we don't want that, so let's edit the
handleSubmit
function.const handleSubmit = async(e) => {
e.preventDefault();
// Sign up code here.
await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
.then(result => {
// Update the nickname
result.user.updateProfile({
displayName: user.nickname,
});
// URL of my website.
const myURL = { url: 'http://localhost:3000/' }
// Send Email Verification and redirect to my website.
result.user.sendEmailVerification(myURL)
.then(() => {
setUser({
...user,
verifyEmail: `Welcome ${user.nickname}. To continue please verify your email.`,
})
})
.catch(error => {
setUser({
...user,
error: error.message,
})
})
// Sign Out the user.
firebase.auth().signOut();
}).catch(error => {
// Update the error
setUser({
...user,
error: error.message,
})
})
}
We added 3 new things.
myURL
is an object that contains the url of my website.result.user.sendEmailVerification()
send an email verification and we passed myURL
object to add a link to redirect us to our website.firebase.auth().signOut()
signed us out, so that we do not log in automatically and wait for the email confirmation.The Log in is easy. Actually is similar to the previous code.
import React, { useState } from 'react';
import { useFirebaseApp } from 'reactfire';
import 'firebase/auth'
import './Signup.css';
const Login = () => {
// User State
const [user, setUser] = useState({
email: '',
password: '',
error: '',
});
// onChange function
const handleChange = e => {
setUser({
...user,
[e.target.name]: e.target.value,
error: '',
})
};
// Import firebase
const firebase = useFirebaseApp();
// Submit function (Log in user)
const handleSubmit = e => {
e.preventDefault();
// Log in code here.
firebase.auth().signInWithEmailAndPassword(user.email, user.password)
.then(result => {
if (!result.user.emailVerified) {
setUser({
...user,
error: 'Please verify your email before to continue',
})
firebase.auth().signOut();
}
})
.catch(error => {
// Update the error
setUser({
...user,
error: error.message,
})
})
}
return (
<>
<h1>Log In</h1>
<form onSubmit={handleSubmit}>
<input type="text" placeholder="Email" name="email" onChange={handleChange}/><br />
<input type="password" placeholder="Password" name="password" onChange={handleChange}/><br />
<button type="submit">Log in</button>
</form>
{user.error && <h4>{user.error}</h4>}
</>
)
};
export default Login;
The most relevant changes are:
createUserWithEmailAndPassword()
, we use signInWithEmailAndPassword()
.Log out is just a button that shows up only when the user is connected.
import React from 'react';
import { useFirebaseApp } from 'reactfire';
import 'firebase/auth'
const Logout = () => {
// Import firebase
const firebase = useFirebaseApp();
// Log out function
const handleClick = () => {
firebase.auth().signOut();
}
return (
<>
<button type="button" onClick={handleClick}>Log Out</button>
</>
)
};
export default Logout;
We use
firebase.auth().signOut()
. The same function that we use to prevent automatically logged in.And practically we are done.
If we want to know if the user is connected or not, we can use
useUser
function from reactfire
.import React from 'react';
import Signup from './Signup';
import Login from './Login';
import Logout from './Logout';
import { useUser } from 'reactfire';
import './App.css';
function App() {
const user = useUser();
return (
<div className="App">
{
user &&
<Logout />
}
{
!user &&
<>
<Signup />
<Login />
</>
}
</div>
);
}
export default App;
I put it in the App file to render the components depending if the user is connected or not.
You can see the entire repo here.