Authentication and Authorization in React Apps

Authentication and Authorization in React Apps

TypeScript For Kids

$ 5,00

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 requests
  • jwt-decode for decoding JWT tokens
  • react-router-dom for routing
  • styled-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 registration
  • POST /api/login for user login
  • GET /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

Leave a Reply