Authentication with React and Express: A Modern Web App Guide

Learn how to implement secure authentication in your web app using React and Express. Step-by-step guide with tips, code samples, and best practices.


Back to Home

Table of content

Introduction to Authentication with React and Express

Authentication is a cornerstone of modern web applications. When building a full-stack app with React (for the frontend) and Express (for the backend), securing user data and ensuring safe user sessions is just as important as delivering great features. In this article, we’ll walk you through how to implement authentication in a typical React and Express setup, complete with code examples and best practices.

Why Use React and Express for Authentication?

  • Separation of concerns: React handles the UI, Express manages API routes and business logic.
  • Scalability: Easily scale each component as your app grows.
  • Flexibility: Choose authentication methods (JWT, sessions, OAuth) that fit your needs.

Common Authentication Approaches

Two popular strategies for authentication with React and Express are:

  • Session-based Authentication: Uses cookies to maintain a user’s session.
  • Token-based Authentication (JWT): Issues a token on login that’s stored and sent with each request.

Why JWT is Popular with SPAs (Single Page Applications)

  • Stateless: Scales easily across distributed environments.
  • Client-side storage: Easily manages authentication state.

Setting Up Express Backend for Authentication

  1. Install Dependencies
    npm install express bcryptjs jsonwebtoken cors
  2. Create the User Model (Simple Example)
    const users = []; // Replace with a proper database in production
  3. Register Route
    const express = require('express');
    const bcrypt = require('bcryptjs');
    const router = express.Router();
    
    router.post('/register', async (req, res) => {
      const { username, password } = req.body;
      const hashedPassword = await bcrypt.hash(password, 10);
      users.push({ username, password: hashedPassword });
      res.status(201).send('User registered!');
    });
    
  4. Login Route (with JWT)
    const jwt = require('jsonwebtoken');
    
    router.post('/login', async (req, res) => {
      const { username, password } = req.body;
      const user = users.find(u => u.username === username);
      if (!user || !(await bcrypt.compare(password, user.password))) {
        return res.status(400).send('Invalid credentials');
      }
      const token = jwt.sign({ username }, 'your_jwt_secret', { expiresIn: '1h' });
      res.json({ token });
    });
    
  5. Protected Route Example
    function authenticateToken(req, res, next) {
      const authHeader = req.headers['authorization'];
      const token = authHeader && authHeader.split(' ')[1];
      if (!token) return res.sendStatus(401);
    
      jwt.verify(token, 'your_jwt_secret', (err, user) => {
        if (err) return res.sendStatus(403);
        req.user = user;
        next();
      });
    }
    
    router.get('/profile', authenticateToken, (req, res) => {
      res.json({ message: `Welcome, ${req.user.username}` });
    });
    

React Frontend: Handling Authentication

  1. Install Axios For API Requests
    npm install axios
  2. Login Component Example
    import React, { useState } from 'react';
    import axios from 'axios';
    
    function Login() {
      const [username, setUsername] = useState('');
      const [password, setPassword] = useState('');
      const [token, setToken] = useState(null);
    
      const handleSubmit = async (e) => {
        e.preventDefault();
        try {
          const res = await axios.post('http://localhost:5000/login', { username, password });
          setToken(res.data.token);
          localStorage.setItem('token', res.data.token);
        } catch {
          alert('Login failed');
        }
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <input value={username} onChange={e => setUsername(e.target.value)} placeholder="Username" />
          <input type="password" value={password} onChange={e => setPassword(e.target.value)} placeholder="Password" />
          <button type="submit">Login</button>
        </form>
      );
    }
    
    export default Login;
    
  3. Access Protected Routes (with Token)
    async function getProfile() {
      const token = localStorage.getItem('token');
      const res = await axios.get('http://localhost:5000/profile', {
        headers: { 'Authorization': `Bearer ${token}` },
      });
      console.log(res.data);
    }
    

Best Practices

  • Never store JWTs in localStorage for highly sensitive apps – consider HTTPOnly cookies for added security.
  • Always hash passwords before storing them.
  • Use HTTPS to protect user credentials and tokens in transit.
  • Validate JWTs on every protected request on your backend.

Conclusion

By combining React on the front end and Express on the back end, implementing authentication is both robust and flexible. With these examples and best practices, you’re well on your way to securing your full-stack applications. If you’re building a project for fulldev.pl or any other platform, following these guidelines will help create safe and user-friendly web applications.

Authentication
Express
JWT
nodejs
React
security
Web Development