This project is designed to provide a basic user authentication system entirely on the client side using React and Redux, allowing users to login, register, and logout. Authentication actions and state management are managed locally, with user data stored in the browser's local storage.
Approach
- Project Setup : Created a React application is using create-react-app and Install Redux and React-Redux to manage the application's state
- State Management: Initial state includes token and user data retrieved from local storage.
- Reducer: Make LOGIN_SUCCESS to validates credentials and sets token. REGISTER_SUCCESS adds new user and LOGOUT clears token from local storage.
- Components: Make Login, Register, and Logout components and handle user authentication and dispatch actions.
- Conditional Rendering : Authenticated users see the Home component and Logout button. Unauthenticated users see the Login and Register components.
Step to Create Application
Step 1: Create a React Application named 'auth-app' and navigate to it using this command.
npx create-react-app auth-app
cd auth-app
Step 2: Install required packages and dependencies.
npm install react-redux redux Project Structure:
Project Structure

Updated dependencies in package.json file:
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1"
},
Example: This example shows the implementation of the above-explained approach.
/* App.css */
button {
padding: 10px 20px;
background-color: rgba(204, 207, 205, 0.74);
margin: 10px 5px;
cursor: pointer;
}
button:hover {
background-color: rgba(9, 221, 9, 0.788);
}
input {
padding: 10px 20px;
}
#App {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
form {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
}
#home {
display: flex;
gap: 10px;
}
// store.js
import { createStore } from 'redux';
// Action types
const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
const LOGOUT = 'LOGOUT';
const REGISTER_SUCCESS = 'REGISTER_SUCCESS';
// Action creators
export const login = (credentials) => ({
type: LOGIN_SUCCESS,
payload: credentials,
});
export const logout = () => ({
type: LOGOUT,
});
export const register = (userData) => ({
type: REGISTER_SUCCESS,
payload: userData,
});
// Initial state
const initialState = {
token: localStorage.getItem('token') || null,
users: JSON.parse(localStorage.getItem('users')) || [],
};
// Reducer
const authReducer = (state = initialState, action) => {
switch (action.type) {
case LOGIN_SUCCESS:
const user = state.users.find(
(user) => user.username === action.payload.username &&
user.password === action.payload.password
);
if (user) {
let token = tokenGenerator();
localStorage.setItem('token', token);
return { ...state, token };
} else {
console.error('Login error: Invalid credentials');
return state;
}
case REGISTER_SUCCESS:
const updatedUsers = [...state.users, action.payload];
localStorage.setItem('users', JSON.stringify(updatedUsers));
return { ...state, users: updatedUsers };
case LOGOUT:
localStorage.removeItem('token');
return { ...state, token: null };
default:
return state;
}
};
// Create store
const store = createStore(authReducer);
export default store;
function tokenGenerator() {
let str = 'abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
let token = ''
for (let i = 1; i <= 20; i++) {
token += str[parseInt(Math.random() * str.length)]
}
return token;
}
// App.js
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { login, logout, register } from './store';
import './App.css'
const Login = ({ onChange, onSubmit }) => {
return (
<form onSubmit={onSubmit}>
<input type="text" name="username"
placeholder="Username"
onChange={onChange} />
<input type="password" name="password"
placeholder="Password"
onChange={onChange} />
<button type="submit">Login</button>
</form>
);
};
const Register = ({ onChange, onSubmit }) => {
return (
<form onSubmit={onSubmit}>
<input type="text" name="username"
placeholder="Username"
onChange={onChange} />
<input type="password" name="password"
placeholder="Password"
onChange={onChange} />
<input type="email" name="email"
placeholder="Email"
onChange={onChange} />
<button type="submit">Register</button>
</form>
);
};
const Logout = ({ onLogout }) => {
return <button onClick={onLogout}>Logout</button>;
};
const App = () => {
const dispatch = useDispatch();
const token = useSelector((state) => state.token);
const [credentials, setCredentials] = useState({ username: '',
password: '', email: '' });
const handleChange = (e) => {
setCredentials({ ...credentials, [e.target.name]: e.target.value });
};
const handleLogin = (e) => {
e.preventDefault();
dispatch(login({ username: credentials.username,
password: credentials.password }));
};
const handleRegister = (e) => {
e.preventDefault();
dispatch(register(credentials));
};
const handleLogout = () => {
dispatch(logout());
};
const [loginFlage, setLoginFlage] = useState(false)
const [signFlage, setSignFlage] = useState(false)
const displayHandle = (fn1, fn2) => {
fn1(e => !e)
fn2(false)
}
return (
<div id='App'>
<h2><img src=
'https://media.geeksforgeeks.org/gfg-gg-logo.svg' alt='gfg_logo' /> {" "} User Auth App</h2>
<div>
{
token ? (
<div id='home'>
<h3>Dear User, Your are log in successfully. </h3>
<Logout onLogout={handleLogout} />
</div>
)
: (
<>
<button onClick={e => displayHandle(setLoginFlage, setSignFlage)} >Log In</button>
<button onClick={e => displayHandle(setSignFlage, setLoginFlage)} >Sign Up</button>
{loginFlage && <Login onChange={handleChange} onSubmit={handleLogin} />}
{signFlage && <Register onChange={handleChange} onSubmit={handleRegister} />}
</>
)}
</div>
</div>
);
};
export default App;
// index.js
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "react-redux";
import store from "./store";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
Output: