What is Context API in React? With an Authentication Example

Introduction
As React apps grow, managing and sharing state between components becomes complex. That's where the Context API comes in — a built-in feature in React that provides a simpler and cleaner alternative to prop drilling or heavy state management libraries like Redux.
What is Context API?
Context API allows you to create global variables or state that can be passed around the component tree, without the need to manually pass props through every level.
Core Components of Context API
React.createContext()
- Creates a new Context object.Provider (
<MyContext.Provider>
) -Wraps the part of your app where you want the context to be available.Consumer or
useContext(MyContext)
- Allows access to the context data inside any child component.
When to Use It
Sharing authentication state.
Managing themes, language, or user preferences.
Handling cart or UI state globally.
Project Example: Authentication System Using Context API
We’ll build a system where:
The user logs in and gets a token.
The token is stored in Context API and localStorage.
The token is accessible app-wide without prop drilling.
No API calls are made from the context itself (only in components).
Folder Structure
src/
├── components/
│ └── Login.jsx
├── context/
│ └── AuthContext.jsx
├── pages/
│ └── Home.jsx
│ └── Dashboard.jsx
├── routes/
│ └── router.jsx
└── App.jsx
Step-by-Step Implementation
Create Auth Context — src/context/AuthContext.jsx
import { createContext, useContext, useState } from 'react';
const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [token, setToken] = useState(() => localStorage.getItem('token'));
const login = (newToken) => {
setToken(newToken);
localStorage.setItem('token', newToken);
};
const logout = () => {
setToken(null);
localStorage.removeItem('token');
};
return (
<AuthContext.Provider value={{ token, login, logout }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
Notes:
We initialize the token from
localStorage
to persist it across reloads.login()
andlogout()
update both state and localStorage.
Define Routes — src/routes/router.jsx
import { createBrowserRouter } from 'react-router-dom';
import Home from '../pages/Home';
import Dashboard from '../pages/Dashboard';
import Login from '../components/Login';
const router = createBrowserRouter([
{ path: '/', element: <Home /> },
{ path: '/dashboard', element: <Dashboard /> },
{ path: '/login', element: <Login /> }
]);
export default router;
App Entry Point — src/App.jsx
import { RouterProvider } from 'react-router-dom';
import router from './routes/router';
import { AuthProvider } from './context/AuthContext';
function App() {
return (
<AuthProvider>
<RouterProvider router={router} />
</AuthProvider>
);
}
export default App;
Login Component — src/components/Login.jsx
import { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { login } = useAuth();
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const res = await axios.post('https://your-api.com/api/users/login', {
email,
password
});
login(res.data.token);
navigate('/dashboard');
} catch (err) {
console.error('Login failed:', err);
}
};
return (
<form onSubmit={handleSubmit}>
<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>
</form>
);
};
export default Login;
Home Page — src/pages/Home.jsx
const Home = () => {
return <h1>Welcome to Home Page</h1>;
};
export default Home;
Dashboard — src/pages/Dashboard.jsx
import { useAuth } from '../context/AuthContext';
const Dashboard = () => {
const { token, logout } = useAuth();
return (
<div>
<h1>Dashboard</h1>
{token ? (
<>
<p>Your token: {token}</p>
<button onClick={logout}>Logout</button>
</>
) : (
<p>You are not logged in.</p>
)}
</div>
);
};
export default Dashboard;
Final Thoughts
Context API is great for sharing global data like auth state across your app.
You should not use Context for all state — only for truly global needs (like auth).
Using localStorage in combination with Context ensures persistence across refreshes.
Subscribe to my newsletter
Read articles from Surajit Das directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
