Authentication System with React's Context API


Introduction
Managing user authentication in a React application can become complex as your application grows. React's Context API offers a streamlined approach to handle authentication, including login, registration, and token management. In this post, we'll walk through creating an authentication system using the Context API with practical code examples.
Setting Up the Auth Context
First, we need to create an authentication context to manage the authentication state and provide necessary actions like login and register.
import React, { createContext, useState } from 'react'; // Create a Context const AuthContext = createContext(); const AuthProvider = ({ children }) => { const [authState, setAuthState] = useState({ token: null, user: null, }); const login = (token, user) => { setAuthState({ token, user }); }; const logout = () => { setAuthState({ token: null, user: null }); }; const register = (token, user) => { setAuthState({ token, user }); }; return ( <AuthContext.Provider value={{ authState, login, logout, register }}> {children} </AuthContext.Provider> ); }; export { AuthContext, AuthProvider };
In this example, AuthContext
is created with default values. The AuthProvider
component manages the authentication state using the useState
hook and provides login
, logout
, and register
functions.
Implementing the Login Component
Next, let's create a login component that uses the AuthContext
to log in a user and store the authentication token.
import React, { useState, useContext } from 'react'; import { AuthContext } from './AuthContext'; const Login = () => { const [credentials, setCredentials] = useState({ username: '', password: '' }); const { login } = useContext(AuthContext); const handleSubmit = async (e) => { e.preventDefault(); // Simulate API call const token = 'sample-token'; // Replace with real token const user = { username: credentials.username }; login(token, user); }; return ( <form onSubmit={handleSubmit}> <input type="text" placeholder="Username" value={credentials.username} onChange={(e) => setCredentials({ ...credentials, username: e.target.value })} /> <input type="password" placeholder="Password" value={credentials.password} onChange={(e) => setCredentials({ ...credentials, password: e.target.value })} /> <button type="submit">Login</button> </form> ); }; export default Login;
In this component, we use the useContext
hook to access the login
function from AuthContext
. The handleSubmit
function simulates an API call to authenticate the user and store the token.
Creating the Registration Component
Similarly, we can create a registration component that uses the register
function from AuthContext
.
import React, { useState, useContext } from 'react'; import { AuthContext } from './AuthContext'; const Register = () => { const [credentials, setCredentials] = useState({ username: '', password: '' }); const { register } = useContext(AuthContext); const handleSubmit = async (e) => { e.preventDefault(); // Simulate API call const token = 'sample-token'; // Replace with real token const user = { username: credentials.username }; register(token, user); }; return ( <form onSubmit={handleSubmit}> <input type="text" placeholder="Username" value={credentials.username} onChange={(e) => setCredentials({ ...credentials, username: e.target.value })} /> <input type="password" placeholder="Password" value={credentials.password} onChange={(e) => setCredentials({ ...credentials, password: e.target.value })} /> <button type="submit">Register</button> </form> ); }; export default Register;
This component follows the same structure as the login component, using the register
function to handle user registration.
Protecting Routes with Auth Context
To protect certain routes and ensure that only authenticated users can access them, we can create a PrivateRoute
component.
import React, { useContext } from 'react'; import { Route, Redirect } from 'react-router-dom'; import { AuthContext } from './AuthContext'; const PrivateRoute = ({ component: Component, ...rest }) => { const { authState } = useContext(AuthContext); return ( <Route {...rest} render={(props) => authState.token ? ( <Component {...props} /> ) : ( <Redirect to="/login" /> ) } /> ); }; export default PrivateRoute;
This component checks if the user is authenticated by looking for a token in the authState
. If the user is not authenticated, they are redirected to the login page.
Conclusion
Using React's Context API to manage authentication state simplifies the process of handling login, registration, and token storage in your application. By providing a central context for authentication, you can easily access and manage the authentication state across your application. This approach not only makes your code cleaner but also enhances the maintainability and scalability of your application. Try integrating the Context API for authentication in your next React project and see the benefits firsthand!