TypeScript For Kids
Join the adventure in “How to Code Cool Stuff: A Fun Guide to TypeScript for Kids”! This magical ebook introduces young adventurers to the exciting world of coding with TypeScript. Packed with easy-to-follow lessons, interactive examples, and fun challenges, it’s the perfect companion for young minds eager to explore the wonders of programming. Start your…
Authentication and authorization are crucial aspects of any web application. Authentication verifies the identity of users, while authorization determines their access levels. In this article, we will explore how to implement authentication and authorization in React applications using JWT (JSON Web Tokens), React Router, and a custom backend API.
Setting Up the React Project
First, let’s set up a new React project using Create React App. If you don’t have Create React App installed, you can install it globally:
npm install -g create-react-app
Create a new project:
npx create-react-app react-auth-app
cd react-auth-app
Installing Dependencies
We will need several dependencies for our project:
axios
for making HTTP requestsjwt-decode
for decoding JWT tokensreact-router-dom
for routingstyled-components
for styling (optional)
Install these dependencies:
npm install axios jwt-decode react-router-dom styled-components
Backend API
For simplicity, we’ll assume you have a backend API that handles user registration, login, and protected routes. The API endpoints are:
POST /api/register
for user registrationPOST /api/login
for user loginGET /api/protected
for a protected route
Creating the Authentication Context
We’ll use the Context API to manage authentication state across the application. Create a new file AuthContext.js
:
import React, { createContext, useState, useEffect } from 'react';
import jwtDecode from 'jwt-decode';
import axios from 'axios';
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [authTokens, setAuthTokens] = useState(localStorage.getItem('tokens') ? JSON.parse(localStorage.getItem('tokens')) : null);
const [user, setUser] = useState(authTokens ? jwtDecode(authTokens.access) : null);
const login = async (email, password) => {
const response = await axios.post('/api/login', { email, password });
setAuthTokens(response.data);
setUser(jwtDecode(response.data.access));
localStorage.setItem('tokens', JSON.stringify(response.data));
};
const logout = () => {
setAuthTokens(null);
setUser(null);
localStorage.removeItem('tokens');
};
useEffect(() => {
if (authTokens) {
setUser(jwtDecode(authTokens.access));
}
}, [authTokens]);
return (
<AuthContext.Provider value={{ authTokens, user, login, logout }}>
{children}
</AuthContext.Provider>
);
};
Creating Protected Routes
Next, we’ll create a component to protect certain routes. Create a new file ProtectedRoute.js
:
import React, { useContext } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AuthContext } from './AuthContext';
const ProtectedRoute = ({ component: Component, ...rest }) => {
const { user } = useContext(AuthContext);
return (
<Route
{...rest}
render={props => {
if (!user) {
return <Redirect to="/login" />;
}
return <Component {...props} />;
}}
/>
);
};
export default ProtectedRoute;
Creating the Login Component
Now, let’s create the login component. Create a new file Login.js
:
import React, { useState, useContext } from 'react';
import { AuthContext } from './AuthContext';
import { useHistory } from 'react-router-dom';
const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { login } = useContext(AuthContext);
const history = useHistory();
const handleSubmit = async (e) => {
e.preventDefault();
await login(email, password);
history.push('/protected');
};
return (
<div>
<h2>Login</h2>
<form onSubmit={handleSubmit}>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<button type="submit">Login</button>
</form>
</div>
);
};
export default Login;
Creating the Protected Component
Create a new file Protected.js
:
import React, { useContext, useEffect, useState } from 'react';
import { AuthContext } from './AuthContext';
import axios from 'axios';
const Protected = () => {
const { authTokens } = useContext(AuthContext);
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const result = await axios.get('/api/protected', {
headers: {
Authorization: `Bearer ${authTokens.access}`,
},
});
setData(result.data);
};
fetchData();
}, [authTokens]);
return (
<div>
<h2>Protected Page</h2>
{data ? <p>{data.message}</p> : <p>Loading...</p>}
</div>
);
};
export default Protected;
Setting Up Routes
Update your App.js
to set up routing:
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { AuthProvider } from './AuthContext';
import ProtectedRoute from './ProtectedRoute';
import Login from './Login';
import Protected from './Protected';
const App = () => {
return (
<Router>
<AuthProvider>
<Switch>
<Route path="/login" component={Login} />
<ProtectedRoute path="/protected" component={Protected} />
</Switch>
</AuthProvider>
</Router>
);
};
export default App;
Conclusion
By following this guide, you have implemented a basic authentication and authorization system in a React application using JWTs, React Router, and a custom backend API. This setup ensures that only authenticated users can access protected routes and that user credentials are securely managed. This foundation can be extended to include features like user registration, role-based access control, and more sophisticated error handling.
React #Authentication #Authorization #JWT #ReactRouter #FrontendDevelopment #WebDevelopment #AuthenticationInReact #AuthorizationInReact #ProtectedRoutes #ContextAPI #Axios #JWTDecode #ProtectedComponents #ReactHooks #useState #useContext #useEffect