Basic Client-Side Authentication in REACT

Client-side authentication in react using hooks and routes

Shobhit kumar
6 min readJun 5, 2021

Authentication is an important part of every application. Today we are going to implement basic authentication in our react application.

BASIC IDEA TO START WITH

  1. Create routes using react-router-dom.
  2. Create Protected Routes that check whether a user is authenticated or not if the user is authenticated then provide that page otherwise redirect the user to other public pages.
  3. On login/signup make a request with Axios to the server that returns a response containing an authentication token.
  4. Store this token in client-side storage such as sessionStorage, localStorage, and cookies.
  5. Redirect user from login page to the page you want the user to see after login using useHistory component of react-router-dom.
  6. On logout clear the client-side and storage.

As of now, we have an idea of how we are going to implement things. Let’s start creating our authentication system.

So let us quickly build our home, signin, and dashboard components to mimic the basic functionality of the authentication on the client side.
Let us first create a react app with the command npx create-react-app authentication.

After creating the app install necessary dependencies such as react-router-dom and Axios with the command npm i react-router-dom axios.

Now create home.js, signin.js, and dashboard.js files. It’s good to have a folder structure but in this application, we are not following any folder structure.

Inside home.js create the components that you want to be publicly accessible without authentication. For the sake of simplicity, we are creating just a single component inside home.js. An actual home component might contain several other components. Create a component named Home and then export it. Inside Home component along with home page content also create a link to the Signin page using Link component of the react-router-dom for smoother navigation around pages.

Inside signin.js create a component named SignIn and then export it. Inside the component return basic form with input fields for passwords and email or username.

You can read more about using the state hooks here.

Import useState from react inside SignIn component. Now declare state variables for email and password.

Now create methods to change the value of these state variables, we will change the state when some change is made to the input fields.

Create a method to handle the submitting of form.

import React,{useState} from 'react'function SignIn() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')

const handleEmail = (e) => {
setEmail(e.target.value)
}
const handlePassword = (e) => {
setPassword(e.target.value)
}
const handleSubmit = (e) => {
e.preventDefault()
}
return (
<div style={{ textAlign: 'center' }}>
<h1>Signin Page</h1>

<form onSubmit={handleSubmit}>
<label htmlFor='email'>
Email
</label>
<br />

<input
id='email'
type='email'
placeholder='Email'
onChange={handleEmail}
value={email}
/>
<br />
<label htmlFor='password'>
Password
</label>
<br />
<input
id='password'
type='password'
placeholder='Password'
onChange={handlePassword}
value={password}
/>
<br />
<br />
<button type='submit'>Signin</button>
</form>
</div>
)
}
export default SignIn

Inside dashboard.js create the components that you want to protect and these should be accessed only after successfully signing in.

import React from 'react'

function Dashboard() {
return (
<div style={{ textAlign: 'center' }}>
<h1> This is the protected dashboard Page</h1>
<button >Logout</button>
</div>
)
}
export default Dashboard

Now, remove unnecessary stuff from the App.js and import home.js, dashboard.js, signin.js inside it.

Now import BrowserRouter, Route, Switch from react-router-dom and create routes for signin, signup and dashboard.

import Home from './components/home'
import { BrowserRouter, Route, Switch} from 'react-router-dom'
import SignIn from './components/signin'
import Dashboard from './components/dashboard'
function App() {
return (
<div className="App">
<BrowserRouter>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/signin' component={SignIn} />
<Route exact path='/dashboard' component={Dashboard} />
</Switch>
</BrowserRouter>
</div>
);
}
export default App;

We have successfully created our routes and you should be able to see different components on different routes.

Now let’s create our Protected Route Component. This component takes the component that you want to protect and then checks whether the token is available on the client-side if the token does not exist then the user is redirected back to the signin page and if the user is authenticated(token is available inside client-side storage) then the user can access the protected component.

const ProtectedRoute = ({ component: Component, ...rest }) => ( 
<Route {...rest} render={(props) => (
sessionStorage.getItem("token")
? <Component {...props} />
: <Redirect to='/signin' />
)} />
)

You can read more about Route render methods of react-router-dom here.

You can read more about Conditional rendering here.

Now in place of the route, we will use a protected route on the component we want to be protected.

Now when the user head over to the dashboard page without authentication (we have not implemented authentication till now) our application should redirect the user back to the login page.

Now to implement authentication logic in our application, first create a dummy server that will provide an authentication token to the client. After that, we will handle that token on the client-side.

Now install express and cors as development dependencies(as we are going to use these dependencies only during the development process) using npm i express cors --save-dev .

You can read more about creating a basic server in express from the express documentation.

Create server.js file and create a basic server inside it. Also, create dummy user data. We will use these dummy credentials for sign-in purpose.

We have used app.use(cors()) to enable cors and app.use(express.json()) to parse incoming requests.

Add "server": "node ./src/server.js" inside scripts block of package.json to create a script to run our dummy server. We can now run our server using npm run server.

Now create a new file auth.js that will handle authentication-related stuff such as logging in a user, logging out user, storage of token, and redirecting users when logging in and out.

We will be using react context API to pass the data between the components and useHistory component of react-router-dom to redirect the user to different pages after receiving the response from the server.

You can read more about creating and using context here.

Inside auth.js file import createContext, Axios, and useHistory.

Now create and export a new context named AuthContext and create a component named Auth. We will create methods for handling sign-in and log-out inside our Auth component and then pass these methods as values to the AuthContext providers.

Let us pass destructured prop children as an argument to Auth component. We will pass these children inside AuthContext providers so that the components wrapped inside Auth component (children) would have access to the values provided by the AuthContext provider.

Inside Auth create the handleSignIn and handleLogout method. Inside handleSignIn method we will take login credentials as arguments and use these credentials to make post request using axios. After receiving the response we will store it in client-side storage(we are going to use sessionStorage). And then we will redirect the user to the protected dashboard page using useHistory.

Inside handleLogout clear client-side storage(in our case session storage) and then redirect the user back to the signin page.

Inside app.js import auth from auth.js and now wrap Signin and Dashboard routes inside Auth.

Inside signin.js import AuthContext from auth. Also, import useContext from react to use the AuthContext now inside SignIn component destructure handleSignIn from AuthContext. Now inside the handleSubmit method call the handleSignIn method with user credentials.

Also, import AuthContext and useContext inside the dashboard. Now destructure handleLogout from AuthContext.

Now call the handleLogout method when the Logout button is clicked by using the onClick event handler.

Congratulations! Now we have successfully created our basic authentication application.

For registering the user in our application we can add a method to register the user in our auth.js file and pass it down as a value to the authContext provider. Inside the register method, we will create Axios request and pass signup credentials with a POST request to the user registering API and then redirect the user to the dashboard page after successful sign-in.

For making further requests to the server that requires authentication on the server-side we can provide our authentication token with headers in our axios request.

Cheers to reading!

--

--