Introduction
Authentication in React is the process of identifying whether a user is signed in to an application. A React application can display different UI based on authentication state, such as Login, Logout, Profile, and Dashboard screens. In real applications, authentication usually works with a backend or authentication service. In this chapter, we will solve practical React js Authentication Practice questions with Solutions using state, forms, local storage, API calls, and protected UI patterns.
1. What is Authentication in React?
Authentication means verifying the identity of a user.
For example, an application may allow users to:
- Create an account
- Log in
- Log out
- View their profile
- Access private application features
A simple React example can keep track of whether a user is logged in:
import { useState } from "react";
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<div>
{isLoggedIn ? (
<h2>Welcome User</h2>
) : (
<h2>Please Login</h2>
)}
</div>
);
}
export default App;
Here, isLoggedIn represents the current authentication state.
In a real application, this state should normally be connected to a backend or authentication provider rather than trusting only a client-side boolean.
2. Create a Simple Login Form in React
Let’s create a basic login form.
import { useState } from "react";
function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
function handleSubmit(e) {
e.preventDefault();
console.log("Email:", email);
console.log("Password:", password);
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">
Login
</button>
</form>
);
}
export default Login;
The form uses controlled inputs.
When the user submits the form, handleSubmit() receives the entered values.
This example only demonstrates the React UI. It does not authenticate the user against a real server.
3. Create Login and Logout Functionality
We can use React state to demonstrate login and logout behavior.
import { useState } from "react";
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
function login() {
setIsLoggedIn(true);
}
function logout() {
setIsLoggedIn(false);
}
return (
<div>
{isLoggedIn ? (
<div>
<h2>Welcome to your account</h2>
<button onClick={logout}>
Logout
</button>
</div>
) : (
<div>
<h2>Please Login</h2>
<button onClick={login}>
Login
</button>
</div>
)}
</div>
);
}
export default App;
Initially:
Please Login
[Login]
After clicking Login:
Welcome to your account
[Logout]
After clicking Logout, the login screen appears again.
This is a UI demonstration. A real authentication system must verify credentials on a trusted server or authentication service.
4. Show Different UI Based on Authentication State
Authentication state can be used for conditional rendering.
function Dashboard({ isLoggedIn }) {
if (!isLoggedIn) {
return <h2>You must log in first.</h2>;
}
return (
<div>
<h2>Dashboard</h2>
<p>Welcome to your dashboard.</p>
</div>
);
}
function App() {
return <Dashboard isLoggedIn={true} />;
}
export default App;
When the user is authenticated, the dashboard is displayed.
When the user is not authenticated:
You must log in first.
This is a basic example of authentication-based conditional rendering.
5. Store Authentication State in Local Storage
If authentication state is stored only in React state, refreshing the page resets it.
For example:
const [isLoggedIn, setIsLoggedIn] = useState(false);
We can persist a simple client-side preference using localStorage.
import { useEffect, useState } from "react";
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(() => {
return localStorage.getItem("isLoggedIn") === "true";
});
useEffect(() => {
localStorage.setItem(
"isLoggedIn",
String(isLoggedIn)
);
}, [isLoggedIn]);
function login() {
setIsLoggedIn(true);
}
function logout() {
setIsLoggedIn(false);
localStorage.removeItem("isLoggedIn");
}
return (
<div>
{isLoggedIn ? (
<>
<h2>Welcome User</h2>
<button onClick={logout}>Logout</button>
</>
) : (
<button onClick={login}>Login</button>
)}
</div>
);
}
export default App;
Now the example can remember the UI state after a page refresh.
Important: This example is for learning persistence. A real authentication system should not treat a client-controlled isLoggedIn value as proof of authentication.
6. Authenticate a User Using an API
Real applications commonly send login credentials to a backend authentication endpoint.
Example:
import { useState } from "react";
function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
async function handleSubmit(e) {
e.preventDefault();
setError("");
try {
const response = await fetch("/api/login", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
email,
password
})
});
if (!response.ok) {
throw new Error("Login failed");
}
const data = await response.json();
console.log("Login successful:", data);
} catch (error) {
setError(error.message);
}
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">
Login
</button>
{error && <p>{error}</p>}
</form>
);
}
export default Login;
The important flow is:
Login Form
↓
Send Credentials
↓
Backend Authentication
↓
Success / Error
↓
Update Application Authentication State
The backend should perform the actual credential verification.
7. Create an Authentication Context
When many components need authentication information, Context can help avoid passing the same data through many levels of props.
import {
createContext,
useContext,
useState
} from "react";
const AuthContext = createContext(null);
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
function login(userData) {
setUser(userData);
}
function logout() {
setUser(null);
}
return (
<AuthContext.Provider
value={{ user, login, logout }}
>
{children}
</AuthContext.Provider>
);
}
function Profile() {
const { user, logout } = useContext(AuthContext);
if (!user) {
return <h2>Please Login</h2>;
}
return (
<div>
<h2>Welcome, {user.name}</h2>
<button onClick={logout}>
Logout
</button>
</div>
);
}
function App() {
return (
<AuthProvider>
<Profile />
</AuthProvider>
);
}
export default App;
Now components inside AuthProvider can access:
user
login
logout
without receiving them through every intermediate component.
8. Create a Reusable useAuth Hook
We can create a Custom Hook to make authentication context easier to use.
import {
createContext,
useContext,
useState
} from "react";
const AuthContext = createContext(null);
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
function login(userData) {
setUser(userData);
}
function logout() {
setUser(null);
}
return (
<AuthContext.Provider
value={{ user, login, logout }}
>
{children}
</AuthContext.Provider>
);
}
function useAuth() {
return useContext(AuthContext);
}
function Profile() {
const { user, logout } = useAuth();
if (!user) {
return <h2>Please Login</h2>;
}
return (
<div>
<h2>Welcome, {user.name}</h2>
<button onClick={logout}>
Logout
</button>
</div>
);
}
Instead of writing:
useContext(AuthContext)
inside every component, we can use:
useAuth()
This makes authentication-related code cleaner and reusable.
9. Handle Authentication Loading State
When an application checks an existing session with a server, there may be a short period where the authentication status is not known yet.
We can represent this with a loading state.
import { useEffect, useState } from "react";
function AuthStatus() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function checkSession() {
try {
const response = await fetch("/api/me");
if (!response.ok) {
setUser(null);
return;
}
const data = await response.json();
setUser(data.user);
} catch (error) {
setUser(null);
} finally {
setLoading(false);
}
}
checkSession();
}, []);
if (loading) {
return <h2>Checking login...</h2>;
}
if (!user) {
return <h2>Please Login</h2>;
}
return <h2>Welcome, {user.name}</h2>;
}
export default AuthStatus;
There are now three possible states:
Checking login...
↓
┌─────┴─────┐
↓ ↓
Logged In Logged Out
This prevents the application from immediately showing the wrong authentication UI while the session check is still running.
10. Build a Practical React Authentication Flow
Let’s combine the main concepts into a simple authentication flow.
import { useState } from "react";
function App() {
const [user, setUser] = useState(null);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
async function handleLogin(e) {
e.preventDefault();
setError("");
try {
const response = await fetch("/api/login", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
email,
password
})
});
if (!response.ok) {
throw new Error("Invalid email or password");
}
const data = await response.json();
setUser(data.user);
} catch (error) {
setError(error.message);
}
}
function handleLogout() {
setUser(null);
}
if (user) {
return (
<div>
<h2>Welcome, {user.name}</h2>
<p>You are logged in.</p>
<button onClick={handleLogout}>
Logout
</button>
</div>
);
}
return (
<form onSubmit={handleLogin}>
<h2>Login</h2>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">
Login
</button>
{error && <p>{error}</p>}
</form>
);
}
export default App;
How it works
- The user enters an email and password.
- React stores the input values in state.
- The form submits the credentials to the backend.
- The backend verifies the credentials.
- If authentication succeeds, user information is stored in React state.
- The application displays the authenticated UI.
- The user can log out.
- In a real application, logout should also invalidate or clear the server-side session/token according to the authentication architecture.
This is a basic learning example. Production authentication requires secure backend handling, HTTPS, appropriate session/token management, authorization checks, and protection against common web security risks.
Key Takeaways
- Authentication identifies whether a user has successfully signed in.
- React can manage authentication-related UI state using
useState. - A real login should verify credentials through a trusted backend or authentication service.
- Client-side state alone is not proof of authentication.
localStoragecan persist client-side data, but it should not be treated as a secure authentication authority.- Context API can make authentication information available to many components.
- A Custom Hook such as
useAuth()can simplify access to authentication context. - Authentication often needs separate loading, authenticated, and unauthenticated states.
- Login and logout should be connected to the application’s actual authentication mechanism.
- Authentication and authorization are different: authentication identifies the user, while authorization determines what that user is allowed to access.
FAQs
1. What is Authentication in React?
Authentication in React is the process of managing the UI and application state associated with verifying whether a user is signed in. Actual credential verification is normally handled by a backend or authentication service.
2. Can React authenticate a user by itself?
React can create the login interface and manage authentication-related state, but secure credential verification should be handled by a trusted backend or authentication service.
3. Can I store react authentication information in localStorage?
Some non-sensitive client-side information can be stored in localStorage, but sensitive authentication secrets should not be casually stored there. A client-controlled value in localStorage should never be treated as proof that a user is authenticated.
4. What is the difference between Authentication and Authorization?
Authentication answers “Who are you?” Authorization answers “What are you allowed to do?”
For example, logging in is authentication, while checking whether a user can access an admin page is authorization.
5. Why is Context API useful for React Authentication?
Context can make authentication information such as the current user, login function, and logout function available to many components without passing those values through multiple levels of props.
6. What is useAuth() in React?
useAuth() is usually a Custom Hook created by an application to provide convenient access to authentication context.
For example:
const { user, login, logout } = useAuth();
It is not a built-in React Hook.
7. Should authentication state have a loading state?
Yes. When the application needs to check an existing session with a server or authentication provider, a loading state helps prevent the UI from incorrectly showing logged-in or logged-out content before the check finishes.
Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.
