Authenticate users with firebase and react.
Tags: react, firebase, javascript
Published: 2020-02-26 16:57:09



In this article, we are going to make a basic user auth with firebase. If you have experience with any other type of user auth, you probably got frustrated.

Firebase does have a learning curve but I have found it small compared to other alternatives.  

Firebase is going to do a lot of the heavy backend functionality

If you would like to see what this app does here is the "finished" product you can __[here](https://firebaseauthtutorial.surge.sh/login)__

__Why is this tutorial useful?__

This is how to leverage firebase so that you don't have to create your own backend, encrypt your user's passwords or go through the hassle of deploying a backend application.  

__Prerequisites:__ 

1. understanding of JavaScript including how to pass arguments to functions and asynchronous code. 

 

2. understanding of react, context, hooks with [create-react-app](https://www.npmjs.com/package/create-react-app).

3. Text editor of your choice.(I will use [vscode](https://code.visualstudio.com/download))

4. [A Firebase account](https://firebase.com)

5. basic understanding of the command line. 

6. knowledge of git. 

Optional: bash command line/Mac OS. You can do this without it but I’ll be using it for this tutorial. 

first, make a new firebase project by visiting https://firebase.com. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kccguino7xi9mu8o2q3m.png)

Click on a new project.


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/f9up8812lv7qdhzsrb3x.png)


click "my first project" and then you can name your project whatever you want. 

Click continue. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ykbwzi4v5zkx4y6gsc7m.png)


You can choose not to have google analytics and it should not interfere with this tutorial, I left it on, so you will see parts of my code where it’s enabled.


Click continue. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ljczadrd2rh935c9trxp.png)

You will be prompted to select an account. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/52316prga7fm8dqf0kx4.png)

select the default account, then click create project. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/52316prga7fm8dqf0kx4.png)


you should now see this. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zzw1izku3jy2wjfztlwj.png)

you should be in your firebase console for this project. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/upb8h5qgkpsnyof9mxwf.png)

click on authentication on the left side navigation. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4ett85773gm95rkpw8zp.png)

click set up sign-in method. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qlnmluar4eoguo8932zb.png)

here is a wide variety of ways to set up users signing into our apps. We are going to do the easiest way for this tutorial. 


click email and password. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4iefop3njd08yyafiqrr.png)

Click enable. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/yevb49yckz39pnr2rb3q.png)


Save. 

Make sure that it actually got enabled. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tmno7e1au6wzejzhu7pc.png)



Now go to the project overview. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vw8rfi9zyr27g383j4cn.png)

We need to get info about how our app can send and receive firebase data, so we have to get API keys and other sensitive information given to us in the form of an SDK.

Click on the brackets to begin. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zzpeg5dqj7qmlewy87h9..

We will be creating a react app and adding everything inside the script tag to the react project. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xfv1yz2eyav0s3o5z64g.png)

since we don't have a firebaseIndex.js we can't add it yet. 

this is everything we have to do on the firebase console for our project. 

make a new react app. 


```bash 
create-react-app firebaseauthtutorial 
```

cd the app

```bash
cd firebaseauthtutorial
```

this is a good moment to plan out what kind of packages are wanted. these will all be installed via npm.  

1. [firebase](https://www.npmjs.com/package/firebase). if this was an ordinary javascript, we would use the whole script take and the SKD.

2. [react-router-dom](https://www.npmjs.com/package/react-router-dom). 

   this is so that when a user logs in we display components only accessible by users. 

3. [dotenv](https://www.npmjs.com/package/dotenv), the best habit you can have with making apps that contain user data or leveraging APIs' (like this app will) is to ensure that hackers can't get access to your API keys, encryption techniques or other users sensitive info.

   dotenv allows you to save sensitive information as environment wide variables, in a way that you can't publish to a remote repo but still be able to use in your app. 

run an npm install on the command line  for all the packages

_pro tip: make sure that you are in the root directory of the project before you run npm install_

```bash
npm install firebase dotenv react-router-dom
```

now open the project. 

I'm using vscode so this is how from the command line. 

```bash
code .
```

look at the package.json file and you should see the packages that you installed. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nc5cd5ppsxomfyy86yby.png)
_package.json_

__moving SDK firebase in the app.__


before you copy and paste the SDK into our file, its best practice to add the .env file to the .gitignore so that you don't publish your environment variables to github. It is very easy to forget. 

then add the API keys to the .env 

then reference them from the firebaseIndex.js we are about to create to the .env file. 

this way, you are never in danger of publishing your keys while following this tutorial. 



Click on your .gitignore



![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/c26xrt0d2bml7sy5zse3.png)

write .env anywhere in the file


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7q55hb6xy424rev2wn5z.png)


then right-click a blank spot in the root directory. (if you don't have one you can minimize the outline to reveal space.)


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1anf4xm5orqyj55ucc2k.png)


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cji3uwv30gt3p43oxo7z.png)

copy and paste the following variables to the .env file

```
REACT_APP_API_KEY=

REACT_APP_AUTHDOMAIN=

REACT_APP_BASEURL=

REACT_APP_PROJECT_ID=

REACT_APP_STORAGEBUCKET=

REACT_APP_MESSAGING_SENDER_ID=

REACT_APP_APP_ID=

REACT_APP_MEASUREMENT_ID=
```

__Including the quotations__ copy and paste the info from the SDK one by one. API key, auth domain, baseurl ect...

you should have something like this. 


_your info from firebase._

```
REACT_APP_API_KEY="your secret api key"
REACT_APP_AUTHDOMAIN="your secret authdomain"
REACT_APP_BASEURL="your secret baseurl"
REACT_APP_PROJECT_ID="your secret projectid"
REACT_APP_STORAGEBUCKET="your secret storeagebucket"
REACT_APP_MESSAGING_SENDER_ID="your secret messaging sender id"
REACT_APP_APP_ID="your secret app id"
REACT_APP_MEASUREMENT_ID="your secret measurment id"

```

now the easy part. 


Begin by making the folder to keep firebases SDK and the helper methods for the auth. 

try and do this from your text editor. 

by right-clicking the src folder and click new folder. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/958j9vlkp1hpjlq1ddv1.png)

name the folder firebase. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/obi8sbzkke7idguy7a3p.png)

now right-click the firebase folder and add a firebaseIndex.js

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6snxqyc019fow83yakhg.png)

_firebaseIndex.js_. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h2c2ae0g9qthgrz964j3.png)

import firebase at the top of the firebaseIndex.js file along with the features you want from it.

 

```javascript
import firebase from 'firebase'
import 'firebase/auth'
import 'firebase/app'
```

now that your environment variables are already set up app-wide you can copy and paste this SDK to reference your sensitive data inside the firebaseIndex file with the code I provide. 



```javascript
var firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTHDOMAIN,
  databaseURL: process.env.REACT_APP_BASEURL,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGEBUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID,
  measurementId: process.env.REACT_APP_MEASUREMENT_ID
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();

```

add firebase.auth() helper method underneath the analytics() method. 

```javascript

firebase.auth()
```

we are going to need the firebaseConfig object in another file so it needs to be exported 

```javascript
export default {
  firebaseConfig, 
}
```

the whole file should look like this. 

```javascript


import firebase from 'firebase'
import 'firebase/auth'
import 'firebase/app'

var firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTHDOMAIN,
  databaseURL: process.env.REACT_APP_BASEURL,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGEBUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID,
  measurementId: process.env.REACT_APP_MEASUREMENT_ID
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
firebase.auth()

export default {
  firebaseConfig, 
}

```

if you followed these steps you could have pushed to github at any time and it would not have saved your keys. 

__Adding the auth methods.__

inside your firebase folder make a file called auth methods, this is where to keep an object that contains the signin, signup, signout, functions. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rxpr18w0acpwk9113fvr.png)


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kz2e5jt0qxov08jtusg6.png)

at the top import two things, firebaseConfig object and firebase from firebase like so.

```javascript
import firebaseconfig from './firebaseIndex'
import firebase from 'firebase'
```

now make an export and make an auth methods object. 

```javascript
export const authMethods = {

// firebase helper methods go here... 

}
```

we are going to send this to context where this will be the top of a chain of methods that link all the way to the form for signin. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qu78701foby0ns496yoj.png)

these are going to be key/value pairs that we give anonymous functions for signing in. 

```javascript

 export const authMethods = {
  // firebase helper methods go here... 
  signup: (email, password) => {

    },
  signin: (email, password) => {

    },
  signout: (email, password) => {

    },
  }
```

this looked really unusual the first time I saw it. This will make a lot more sense after we start calling on it from context. 

this is from the [firebase documentation for user auth](https://firebase.google.com/docs/auth/web/start?authuser=0).

```javascript
signup: (email, password) => {
    firebase.auth().createUserWithEmailAndPassword(email,password) 
      .then(res => {
        console.log(res)
      })
      .catch(err => {
        console.error(err)
      })
    },
``` 

I want to test if this code works before I start adding the other methods. 

to do that build the context and signup form and see if firebase will respond. 


__Creating context for our application.__ 

right-click on the src folder and make a new folder called provider.


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/iolz0m0lmjz29p5uohtp.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/15vizl132e9456izwxp5.png)
 
right-click on provider and make a file called AuthProvider.js


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zbltch6w4kmwkssrwgwz.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/33ixjwpnk0k79t6c21vo.png)

make a functional component, add props. 

```javascript
import React from 'react';

const AuthProvider = (props) => {
  return (
    <div>
      
    </div>
  );
};

export default AuthProvider;

```

outside of the function, make a firebaseAuth variable and make it equal to react context. 

```javascript
export const firebaseAuth = React.createContext()
```

we have to export it so that we can access the useContext hook.

erase the div tags and make the provider inside of the return for the AuthProvider I'm not going to explain everything that is happening here but if you want to know more about context this is an article where I explain [context and the useContext hook](https://dev.to/tallangroberg/context-and-the-usecontext-hook-1g8l).


```javascript
const AuthProvider = (props) => {
  return (
    <firebaseAuth.Provider
    value={{
      test: "context is working"
    }}>
      {props.children}

    </firebaseAuth.Provider>
  );
};
```
_AuthProvider.js_

now we need to wrap our App.js in the AuthProvider component in the index.js file. 

we also need to import our ability to route components dynamically, since we are already in this file, add BrowserRouter from react-router-dom. 

start by importing the AuthProvider and BrowserRouter at the top.

```javascript
import AuthProvider from './provider/AuthProvider'
import {BrowserRouter} from 'react-router-dom'
```

then make an App sandwich with BrowserRouter and AuthProvider. 

```javascript
ReactDOM.render(
<BrowserRouter>
  <AuthProvider>
    <App />
  </AuthProvider>
</BrowserRouter>
, document.getElementById('root'));
```

two things, 

go to the App.js, at the top change how react is imported to include useContext and  React.

import {firebaseAuth} so that we can destructure the test key/value pair out of it like this. 

```javascript
import React, {useContext} from 'react';
import {firebaseAuth} from './provider/AuthProvider'
```


inside the function destructure test from the firebaseAuth variable.

console.log test.  

```javascript
   const {test} = useContext(firebaseAuth)
    console.log(test)

```

go back to the terminal and start the server. 

```bash
npm start
```

inspect with the dev tools and you should see this.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ueli4qgew7jhx1q7dk5t.png)

__connecting to authMethods__

now that we have context App wide, go back to the AuthProvider.js and import the authMethods. 

```javascript
import {authMethods} from '../firebase/authmethods'
```

This file to be the middle man between firebase and the Signup component we are about to make,

that means all the stateful logic will be housed here. 

make a function called handleSignup inside the AuthProvider.

```javascript
const handleSignup = () => {
    // middle man between firebase and signup 

  }
```

Pass it as a value in the firebaseAuth.Provider 

```javascript
 <firebaseAuth.Provider
    value={{
      //replaced test with handleSignup
      handleSignup
    }}>
      {props.children}

    </firebaseAuth.Provider>

```

now change test with handleSignup in the App.js

```javascript
 const {handleSignup} = useContext(firebaseAuth)
    console.log(handleSignup)

```
_App.js_

you should see

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w3l7715rhxsrc393nzce.png)

in the AuthProvider, add the authMethod.signup() to the handleSignup.

```javascript
  const handleSignup = () => {
    // middle man between firebase and signup 
    console.log('handleSignup')
    // calling signup from firebase server
    return authMethods.signup()
  }
```

make a components folder and Signup.js component, recreate the same functionality where we want it to end up so that we can define our routing in the App.js


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lydehlps203vywn800mb.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nb2rbldo7oj4hyx1ycye.png)

make the Signup.js



![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/s9tstuimehix3itu8wki.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/j359wjpfn4bah9v16317.png)

make a basic component

```javascript

// add useContext
import React, {useContext} from 'react';

const Signup = () => {

    
  return (
    <div>
      Signup
    </div>
  );
};

export default Signup;
```

destructure the handleSignup function out of context just like in the App.js

```javascript
const {handleSignup} = useContext(firebaseAuth)
    console.log(handleSignup)
```
__

in the App.js add the beginnings of react-router-dom by removing the boilerplate and adding Switch and Route, setting the signup to be rendered by the Route.

```javascript

import {Route, Switch} from 'react-router-dom'
import Signup from './component/Signup'
```

_App.js_

```javascript
 return (
    <>
    {/* switch allows switching which components render.  */}
      <Switch>
        {/* route allows you to render by url path */}
        <Route exact path='/' component={Signup} />

      </Switch>
    </>
  );
```
if everything worked you should see a white screen with signup. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/l59b8ore82j1kxw5zjw0.png)

make a signup form.

```javascript
return (
    <form>
      {/* replace the div tags with a form tag */}
      Signup
      {/* make inputs  */}
      <inputs  />
      <button>signup</button>
    </form>
  );
```

at this point, it might be tempting to make state here. but we want the context to be the single source of truth so that if a user toggles between login and signup, whatever they typed in will persist. 

go back to the AuthProvider and start setting up state. 

we need a piece of state for a token from firebase and for user data.

import useState next to React. 

```javascript
import React, {useState} from 'react';
```

_AuthProvider.js_

the pieces of state that we want will be.

1. token as null (then a string once we get a token from firebase), more about  [json web tokens](https://jwt.io/introduction/). 

2. input as an object with email and password both strings.

3. errors as an array, so that error messages can be displayed to the users. 


add those states to the AuthProvider.js

```javascript

const [inputs, setInputs] = useState({email: '', password: ''})
  const [errors, setErrors] = useState([])
  const [token, setToken] = useState(null)

```

add inputs to the value object of the provider. 


```javascript
<firebaseAuth.Provider
    value={{
      //replaced test with handleSignup
      handleSignup,
      inputs,
      setInputs,
      
    }}>

```

in the Signup.js get them from the authContext with the useContext hook like this. 

```javascript
  const {handleSignup, inputs, setInputs} = useContext(firebaseAuth)
```

make handleChange and handleSubmit functions as basic forms. 


```javascript
const handleSubmit = (e) => {
    e.preventDefault()
    console.log('handleSubmit')
    
  }
  const handleChange = e => {
    const {name, value} = e.target
    console.log(inputs)
    setInputs(prev => ({...prev, [name]: value}))
  }
```

change the form and input fields to work with the form functions. 

```javascript
<form onSubmit={handleSubmit}>
      {/* replace the div tags with a form tag */}
      Signup
      {/* make inputs  */}
      <input onChange={handleChange} name="email" placeholder='email' value={inputs.email} />
      <input onChange={handleChange} name="password" placeholder='password' value={inputs.password} />
      <button>signup</button>
    </form>

```

if you did everything correctly and ran a test that looks like this...

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y5z999l46yg5uvr25l3y.png)

here is the error message you would have gotten. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mrnqv8iqkdi69eiwflfa.png)

the reason we got this error is that we didn't pass the authMethods.signup the email and password arguments that it was expecting. 

pass inputs.email and inputs.password into authMethods.signin 

```javascript
authMethods.signup(inputs.email, inputs.password)
```

when you do a test like this.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/knab9m0aox1f7z2n29k0.png)

 you should get a response like this.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/978cuy3g3vkgdoi2ghm3.png)

but if you try and do it twice you will get an error. 

 ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fl75zxhqgrhnuhmi9plr.png)

this is because you can't do this twice. all of the emails have to be unique. 

to make it so that the error message displays to the user we have to do the following. 

1. in the AuthProvider.js, pass setErrors as an argument along with email and password,

  this is the only way I could figure out how to do this. whenever you do have to pass more than one argument to a function you should have a good justification.  

2. in the authMethods.js on the signup(), add the third argument at the top and in the .catch, we will have the error messages save to state in the errors array.

3. have the error display to the screen by passing it to the Signup.js and mapping through the array. 

1. 
```javascript
//sending setErrors
  authMethods.signup(inputs.email, inputs.password, setErrors)
console.log(errors)
```

now add the setErrors message along with email and password.

_AuthProvider.js_
2.
```javascipt
  //catching setErrors
 signup: (email, password, setErrors) => {
```
_authMethods.js_

change the catch to the setErrors include prev in case it's more than one error

```javascript
.catch(err => {
       //saving error messages here
        setErrors(prev => ([...prev, err.message]))
      })

```

if it worked __and you console logged it__, you should see this error. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ruyfaqgxpexodf72bo4d.png)

3. add errors to the value object of the Provider

```javascript
 <firebaseAuth.Provider
    value={{
      //replaced test with handleSignup
      handleSignup,
      inputs,
      setInputs,
//added errors to send to Signup.js
      errors,
    }}>
      {props.children}
    </firebaseAuth.Provider>

```
_AuthProvider.js_

destructure it from useContext from the Signup.js

```javascript
const {handleSignup, inputs, setInputs, errors} = useContext(firebaseAuth)

```
_Signup.js_

now add a ternary that will only show up if an error occurs. 


```javascript
  <button>signup</button>
      {errors.length > 0 ? errors.map(error => <p style={{color: 'red'}}>{error}</p> ) : null}
    </form>
```

if everything worked you will get your error on the screen. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/iol3gmynbouk2oa5ycg7.png)

if you want to [filter duplicates](https://medium.com/dailyjs/how-to-remove-array-duplicates-in-es6-5daa8789641c) you can find out or see how I did on the repo but this tutorial is getting long and a couple more things to do. 

to make it so that you can enable multiple emails per account. 

go to firebase inside of this project, click on authentication.

click on signin method 

scroll to the bottom and where it says advanced in small black letters. it says one account per email in bold. 

Click the blue change button 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kvzrr83o0i8mmcsgsr1s.png)

click allow multiple accounts with the same email. 

this will help us move faster with testing but don't forget to switch it back later. 


1. The same way that we set an error we are going to save the token to localStorage and the token's state in the AuthProvider. 

2. make it so that we can only see some components if we have a token. 

3. redirect to that page if the token in local storage matches the token in state.

4. repeat the process for signin.

5. erase the token and pushing the user out of the authenticated parts of our app with the login method.

1. go to the AuthProvider.js and add setToken as another argument after setErrors. 

```javascript
//sending setToken function to authMethods.js
 authMethods.signup(inputs.email, inputs.password, setErrors, setToken)
    console.log(errors, token)
```  
_AuthProvider.js_

add this as a 4th argument at the top. 

```javascript
// added the 4th argument
 signup: (email, password, setErrors, setToken) => {
```

inside the .then, underneath the console.log(res)... 

I am about to save you so much time you would have to spend digging through the res object to find the token. 



this is also about to be a little messy with the async code. 


```javascript
signup: (email, password, setErrors, setToken) => {
    firebase.auth().createUserWithEmailAndPassword(email,password) 
      //make res asynchronous so that we can make grab the token before saving it.
      .then( async res => {
        const token = await Object.entries(res.user)[5][1].b
          //set token to localStorage 
          await localStorage.setItem('token', token)
          //grab token from local storage and set to state. 
          setToken(window.localStorage.token)
        console.log(res)
      })
      .catch(err => {
        setErrors(prev => ([...prev, err.message]))
      })
    },
```
_authMethods.js_

now if you make yet another account and go to the browsers dev tools 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vgqi9g2gp329vxwgexk7.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mfv7w276twxvza28dzwr.png)


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3iomrkvi86j2udpp6n5a.png)

__2. signing in __

we are going to copy and paste a lot of what we have for signup and easily configure it for login. 

we will start from the bottom of the component tree by making a Signin component slightly change file by file until it works in the authMethods. 

start by making a new file called Signin.js

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/f2lozjeagtutrnoxm101.png)

copy and paste everything from the Signup.js to the Signin.js

highlight everywhere it says signup and change that to signin 

Click on the name of the react component and Command + d if you are using a mac. Otherwise, you can use ctrl + f and type it in at the top. 

I only had 3 words by remember to change handleSignup to handleSignin using the same method. 

change the button as well. 

Now go to the App.js and import the file. 

```javascript
import Signin from './component/Signin'
```

make sure that component folder on the import is singular.

 add a new route for the Signin

```javascript
<Route exact path='/' component={Signup} />
        <Route exact path='/signin' component={Signin} />

```

your signin component will render now if you type in the http://localhost:3000/signin but as soon as you do click the button it will crash because there is no handleSignin function. 

to fix that we can go to the AuthProvider.js and copy and paste changing the wording just like we did for signup. then add the handleSignin function to the value object. 

```javascript
const handleSignin = () => {
    //changed to handleSingin
    console.log('handleSignin!!!!')
    // made signup signin
    authMethods.signin(inputs.email, inputs.password, setErrors, setToken)
    console.log(errors, token)
  }

```
now to add that function to the firebaseAuth.Provider

```javascript
 <firebaseAuth.Provider
    value={{
      //replaced test with handleSignup
      handleSignup,
      handleSignin,
      inputs,
      setInputs,
      errors,
    }}>
      {props.children}
    </firebaseAuth.Provider>
```
_AuthProvider.js_


now go to authMethods.js and do something similar, instead of createUserWithEmailAndPassword,  change to... signInWithEmailAndPassword() 

```javascript
signin: (email, password, setErrors, setToken) => {
    //change from create users to...
    firebase.auth().signInWithEmailAndPassword(email,password) 
      //everything is almost exactly the same as the function above
      .then( async res => {
        const token = await Object.entries(res.user)[5][1].b
          //set token to localStorage 
          await localStorage.setItem('token', token)
          setToken(window.localStorage.token)
            console.log(res)
      })
      .catch(err => {
        setErrors(prev => ([...prev, err.message]))
      })
    },

```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jockcc4l0u82dzk7xden.png)

if you didn't delete your token from local storage then a token will still be there. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/o4pao73qfq592fixdc04.png)

 almost there!!

1. make a home component and only allow users with tokens to get there. 

2. make a signout button that deletes the token and pushes the user away from the page with react-router-dom.


since you should already be in the authMethods.js we will start from the top and go to the bottom this time. 

this method is really simple compared to the other two because we aren't using firebase to keep user's status there. 

```javascript
//no need for email and password
signout: (setErrors, setToken) => {
      // signOut is a no argument function
    firebase.auth().signOut().then( res => {
      //remove the token
      localStorage.removeItem('token')
        //set the token back to original state
        setToken(null)
    })
    .catch(err => {
      //there shouldn't every be an error from firebase but just in case
      setErrors(prev => ([...prev, err.message]))
      //whether firebase does the trick or not i want my user to do there thing.
        localStorage.removeItem('token')
          setToken(null)
            console.error(err.message)
    })
    },
  }
```

go to AuthProvider.js and make a signout function


```javascript
const handleSignout = () => {
    authMethods.signout()
  }

```

add the method to the Provider

```javascript
setInputs,
errors,
handleSignout,
```



now we need a component for this to be useful which we haven't done yet. 

make a Home.js, and a basic React component inside it. 


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9q86kunn9kytdkv73co4.png)


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/j0qzpp9s1f8mi7dz2mo2.png)

```javascript
import React from 'react';

const Home = (props) => {
  return (
    <div>
      Home
    </div>
  );
};

export default Home;
```

import useContext and firebaseAuth

```javascript
import React, {useContext} from 'react';
import {firebaseAuth} from '../provider/AuthProvider'
```

between return and Home inside the Component, destructure signout from useContext 

```javascript
  const {signout,} = useContext(firebaseAuth)
```

in the return statement. add login successful, then a button to call on signout. 

```javascript
 return (
    <div>
      Home, login successful!!!!!!
      <button onClick={signout}>sign out </button>
    </div>
  );
```

before we can test it, we need to go back up our component tree and change how strict it is to access each component. 

in the App.js we are going to use a ternary statement to make it so that users can't get to the home component without a token saved to state.



import the Home component in the App.js.

```javascript

import Home from './component/Home'
```

destructure the token out of firebaseAuth with useContext

```javascript
  const { token } = useContext(firebaseAuth)
  console.log(token)
```

when you use Route to render the Home component, add a ternary statement checking the data type of the token

this means that setting up the "/" or root URL differently. 

change your Home components route to use the render prop instead of the component prop. and designate the URL paths more strictly.

```javascript
        <Route exact path='/' render={rProps => token === null ? <Signin /> : <Home />} />
        <Route exact path='/signin' component={Signin} />
        <Route exact path='/signup' component={Signup} />
```

in the AuthProvider.js, add the token to the value object. 

```javascript
<firebaseAuth.Provider
    value={{
      //replaced test with handleSignup
      handleSignup,
      handleSignin,
      token,
      inputs,
      setInputs,
      errors,
      handleSignout,
    }}>
      {props.children}
    </firebaseAuth.Provider>
```

now users can signin and signout. One final touch, make it so that when a user signs up, react-router-dom will send them to the home page. 

go to the Signup.js and import withRouter from react-router-dom

```javascript
import {withRouter} from 'react-router-dom'
```

pass the default export to the withRouter higher-order component

```javascript

export default withRouter(Signup);
```

add props to the Signup component

```javascript
const Signup = (props) => {
```

now we have access to prop.history.push("/goAnyWhereInApp")

now make handleSubmit an async function and await the handleSignup and then push to the root URL. 

```javascript
const handleSubmit = async (e) => {
    e.preventDefault()
    console.log('handleSubmit')
    //wait to signup 
    await handleSignup()
    //push home
    props.history.push('/')
  }
```

you might have a delay, but once you get your credentials it will work. 

if you want to publish this sight [here is how with surge.](https://surge.sh/help/getting-started-with-surge) I am a big fan and am doing these firebase tutorials because of a dev who has suffered much at the hands of heroku 

this is the [finished product](https://firebaseauthtutorial.surge.sh/login)

this is the [github](https://github.com/TallanGroberg/firebase-auth-tutorial) give it a star if you can. 

__Finally, that is it__

you now have a static site with powerful backend functionality. 

I will be doing a lot more tutorials on firebase. 

please like and share if you found this tutorial beneficial. 

the [firebase docs](https://firebase.google.com/docs/auth/web/password-auth?authuser=0) are helpful but I have a few things in here that make it so much easier to transpose to a react project. 

if you have anything to say please add it to the comments below.