React JS not accepting cookies from express sever

3 min read 05-10-2024
React JS not accepting cookies from express sever


ReactJS and Express: The Cookie Conundrum

It's a common scenario: you're building a web application with a React frontend and an Express backend. You're ready to implement authentication, and cookies seem like the perfect solution. But then, you hit a snag – your React app simply refuses to accept cookies from your Express server. What's going on?

The Problem: Mismatched Origins

This issue arises because of the way browsers handle cookies and the concept of "Same-Origin Policy." In a nutshell, this policy dictates that a website can only read and write cookies from the same domain (or origin) from which they were set.

Here's a common example:

Server (Express)

const express = require('express');
const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.post('/login', (req, res) => {
  const username = req.body.username;
  const password = req.body.password;

  // Simplified authentication for demonstration
  if (username === 'user' && password === 'password') {
    res.cookie('authToken', 'your_auth_token', { httpOnly: true });
    res.send('Login successful');
  } else {
    res.status(401).send('Invalid credentials');
  }
});

app.listen(3001, () => {
  console.log('Server running on port 3001');
});

Client (React)

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [loggedIn, setLoggedIn] = useState(false);

  useEffect(() => {
    const authToken = document.cookie.split('; ').find(row => row.startsWith('authToken='));
    if (authToken) {
      setLoggedIn(true);
    }
  }, []);

  const handleLogin = async (event) => {
    event.preventDefault();
    const username = event.target.username.value;
    const password = event.target.password.value;

    try {
      const response = await axios.post('http://localhost:3001/login', {
        username,
        password
      });
      setLoggedIn(true);
      console.log('Login successful:', response.data);
    } catch (error) {
      console.error('Login failed:', error);
    }
  };

  return (
    <div>
      {!loggedIn && (
        <form onSubmit={handleLogin}>
          <input type="text" name="username" placeholder="Username" />
          <input type="password" name="password" placeholder="Password" />
          <button type="submit">Login</button>
        </form>
      )}
      {loggedIn && (
        <p>You are logged in!</p>
      )}
    </div>
  );
}

export default App;

In this scenario, the Express server sets the authToken cookie on the response, but the React client running on a different port (e.g., http://localhost:3000) is blocked from accessing it due to the Same-Origin Policy.

The Solution: CORS to the Rescue

The answer lies in Cross-Origin Resource Sharing (CORS). CORS allows your server to explicitly grant permission to clients from different origins to access its resources, including cookies.

Express Server with CORS Enabled

const express = require('express');
const cors = require('cors'); // Import CORS middleware
const app = express();

app.use(cors({
  origin: 'http://localhost:3000', // Specify allowed origin
  credentials: true // Allow cookies
}));

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// ... rest of the code ...

With this setup, the server now explicitly tells the browser that it's okay for the React app at http://localhost:3000 to access resources (including cookies) from the server at http://localhost:3001.

Additional Notes:

  • credentials: true is crucial. It informs the browser that the client is allowed to send credentials (including cookies) along with cross-origin requests.
  • HTTP-Only Cookies: These cookies cannot be accessed by JavaScript on the client-side. This enhances security by making it harder for attackers to steal cookie data.
  • Secure Cookies: In production environments, ensure cookies are set with secure: true to enforce HTTPS transmission.

Key Takeaways:

  • The Same-Origin Policy governs cookie access, preventing clients from different origins from accessing cookies.
  • CORS is the solution to this restriction, allowing your server to grant permission for cross-origin cookie access.
  • Remember to set credentials: true and consider using HTTP-only and secure cookies for enhanced security.

By implementing CORS correctly, you can bridge the gap between your React client and your Express server, enabling seamless cookie-based authentication and a smooth user experience.