React Login, Logout, JWT Authentication Token with React Redux.

suraj yadav
5 min readSep 16, 2021

I will show you how we can right generic code for login and logout with the help of React Redux and after login redirect to dashboard or any other pages.

Install the dependency i.e. npm install redux react-redux redux-thunk

before moving the code let create the folder structure so that we can keep simple.

create the folder _components or component -> auth -> login.js (whatever named you prefer you can keep , it should look like this _components/auth/login.js).

create _components or component -> pages -> Dashboard.js

create folder _actions -> user.actions.js and user.actions.types.js

create folder _helpers -> auth-header.js , store.js , history.js and global.js

create folder _privateRoute -> privateRoute.js

create folder _reducers -> user.reducer.js

create folder _services -> login -> user.service.js

Done.

let first work on redux i.e.( create the dispatch, action and reducer for users)

(Note: assuming you know redux won’t explain the redux part)

# Folder _actions/user.actions.types.jsexport const userActionTypes = {
LOGIN_SUCCESS: 'USERS_LOGIN_SUCCESS',
LOGIN_FAILURE: 'USERS_LOGIN_FAILURE',
LOGOUT: 'USERS_LOGOUT'
};
# Folder _actions/user.actions.js
import { userActionTypes } from './user.actions.types';
export const changeloggedIn = (isLoggedIn, user) => {
return (dispatch) => {
dispatch({
type: userActionTypes.LOGIN_SUCCESS,
payload: { isLoggedIn: isLoggedIn, userData: user }
});
}
};

userActionTypes are just define the what action we are taking and on user.actions.js create the dispatch action i.e (changeLoggedIn).

As created the action and dispatch now its need to be work on reducers part of user.

on folder _reducer -> users.reducer.js

# folder _reducer -> users.reducer.jsimport { userActionTypes } from '../_actions/user.actions.types';const iState = {loggedIn: false,userDetails: {}};const reducer = (state = iState, action) => {if (action.type === userActionTypes.LOGIN_SUCCESS) {
return {
loggedIn: action.payload.isLoggedIn,
userDetails: action.payload.userData
}}
return state;
}
export default reducer;

created the action, dispatch and reducer but data needs to be store so for that we are going work on folder_helpers -> store.js

# _helpers -> store.jsimport { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import reducer from '../_reducers/users.reducer';
const mainReducer = combineReducers({
user : reducer
});
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(mainReducer, composeEnhancers(applyMiddleware(thunk)
));
export default store;

we are done with redux part only thing is remaining we need to provide the data to component we want.

import React, { Component } from 'react';import ReactDOM from 'react-dom';import './index.scss';import App from './App';# index.jsimport React, { Component } from 'react';
import ReactDOM from 'react-dom';
import store from './_helpers/store';
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={store} >
<App />
</Provider>,
document.getElementById('root'));

with the help of Provider pass the data of user to App component.

now will work on login part but before that we need code write some generic code on _helpers folder and private router.

# _helpers -> auth-header.js
export function authHeader(isImage) {
// Return authorization header with jwt tokenlet user = JSON.parse(localStorage.getItem("userDetails"));if (user && user.token) {if (isImage != null && isImage) {return {Authorization: "Bearer " + user.token,};} else {return {"Content-Type": "application/json",Authorization: user.token,// Authorization: "Bearers " + user.token,};}} else {return {};}}

basically we have create the authHeader function so that we can used it later for Authentication the token and let create history.js for routing

# _helpers -> history.jsimport { createBrowserHistory } from "history";
export const history = createBrowserHistory();

_privateRoute -> privateRoute.js

we are now working on router so that we keep router private so that user unable to visit that link without login.

import React from "react";import { Route, Redirect } from "react-router-dom";export const PrivateRoute = ({ component: Component, ...rest }) => {return (<Route{...rest}render={(props) => {return localStorage.getItem("userDetails") ? (<Component></Component>) : (<Redirectto={{ pathname: "/login", state: { from: props.location } }}/>);}}/>);};

create the PrivateRoute function so that it validate the component before login. if user has after login then it will allow the access to that link or component otherwise redirect to login.

now add some routing in index.js file

# index.jsimport React from 'react';
import ReactDOM from 'react-dom';
import Login from "./Components/pages/Login";
import Dashboard from "./Components/pages/Dashboard";
import Notfound from "./Components/pages/notfoundComponet";
import { Router, Switch, Route } from "react-router-dom";
import { PrivateRoute } from "./_privateRoute/privateRoute";
import { history } from "./_helpers/history";
import store from "./_helpers/store";
import { Provider } from "react-redux";
const App = () => {return (<Fragment><Router history={history}><Switch><Route exact path="/login" component={Login} /><PrivateRouteexactpath="/dashboard"component={Dashboard}></PrivateRoute><Route exact component={Notfound} /><Route exact path="*" component={Login}></Route></Switch></Router></Fragment>);};ReactDOM.render(
<Provider store={store} >
<App />
</Provider>,
document.getElementById('root'));

Create the privateRouter for dashboard page so that no one can access without login and also handle the if url not match then it will redirect to page not found.

create also global.js file so that we can keep all global API.

export default class Global {// For Live serverstatic BASE_API_PATH = "paste it here you api";}

now let start working on service part i.e to fetch the API data.

#  _services -> login -> user.service.jsimport Global from "../_helpers/global";import { authHeader } from "../_helpers/auth-header";export const userService = {login,};async function login(email, password) {const requestOptions = {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({ email, password }),};return fetch(Global.BASE_API_PATH + "replace with you api path", requestOptions).then(handleResponse).then((res) => {return res;});function handleResponse(response) {return response.text().then((text) => {
const data = JSON.parse(text);
if (!response.ok) {if (response.status === 401) {}const error = (data && data.message) || response.statusText;return Promise.reject(error);}return data;});}

create to async function one login and other is to handle the error.

Finally now let work on login part i.e _components or component -> auth -> login.js

import React, { Fragment } from "react";import { withRouter } from "react-router-dom";import { userService } from "../../_services/user.service";import { history } from "../../_helpers/history";import { connect } from "react-redux";import { changeloggedIn } from "../../_actions/user.actions";class Login extends React.Component {constructor(props) {super(props);this.state = {email: "",password: "",loginSubmitted: false,};this.doLogin = this.doLogin.bind(this);this.handleChange = this.handleChange.bind(this);this.logout();}handleChange(event) {event.preventDefault();const { name, value } = event.target;this.setState({ [name]: value });}async doLogin(event) {event.preventDefault();this.setState({ loginSubmitted: true });const { email, password } = this.state;userService.login(email, password).then((res) => {if (res.success) {if (res.data.id === 0) {localStorage.removeItem("userDetails");this.clearLoginForm();} else {localStorage.setItem("userDetails", JSON.stringify(res.data));this.props.setLoggedIn(true, res.data);this.clearLoginForm();history.push("/dashboard");}} else {localStorage.removeItem("userDetails");this.clearLoginForm();}},(error) => {localStorage.removeItem("userDetails");this.clearLoginForm();});}clearLoginForm = () => {this.setState({email: "",password: "",});};logout() {localStorage.clear();this.props.setLoggedIn(false, {});}render() {const { email, password } = this.state;return (<div><Fragment><form className="nav" onSubmit={this.doLogin}><h1 className="h3 mb-3 font-weight-normal">Please sign in</h1><div><label htmlFor="inputEmail" className="sr-only">Email address</label><inputtype="email"name="email"id="inputEmail"className="form-control"onChange={this.handleChange}placeholder="Email address"value={email}/></div><div><label htmlFor="inputPassword" className="sr-only">Password</label><inputtype="password"name="password"id="inputPassword"className="form-control"placeholder="Password"onChange={this.handleChange}value={password}/></div><button className="btn btn-lg btn-primary btn-block" type="submit">Sign in</button></form></Fragment></div>);}}const mapStoreToProps = (state) => {return {user: state.user,};};const mapDispatchToProps = (dispatch) => {
return {
setLoggedIn: (isLoggedIn, user) => {dispatch(changeloggedIn(isLoggedIn, user));},};};export default connect(mapStoreToProps, mapDispatchToProps)(withRouter(Login));

create the dologin function and checking if res.data.id === 0 then no user is login otherwise successfully login.

Done.

Thank you :)

This was my first blog hope it will be helpful. it would be great if you provide feedback.

--

--