Comprehensive Guide to Fixing the Issue of Cookies Not Being Sent in Cross-Origin Requests (CORS)

If you have encountered a scenario where the server sets the cookie correctly (visible in the browser response), but in subsequent requests, the browser does not return that cookie to the server, this guide is for you. This issue almost always occurs when the frontend and backend of your project are on two different domains or ports — for example, frontend on app.example.com and API on api.example.com.

Why Does This Happen?

Modern browsers impose two strict security policies to prevent CSRF attacks and session hijacking:

  1. CORS Policy: By default, the browser does not allow cross-origin requests to include credentials (such as cookies) unless the server explicitly permits this.
  2. SameSite Policy: Starting from Chrome 80, cookies are treated with SameSite=Lax behavior by default, meaning they will not be sent in cross-origin requests unless explicitly defined with SameSite=None.

The important point is that to solve this issue, both the client and server sides must be configured correctly. Modifying only one side is not enough.

Step 1: Correct Server Configuration

Three Golden Rules on the Server Side

Rule 1 — Enable Credentials: The server response header must include the following value:

Access-Control-Allow-Credentials: true

Rule 2 — No Wildcard: When credentials are enabled, you cannot use the * wildcard in the Access-Control-Allow-Origin header. You must specify the exact full domain address of the frontend:

Access-Control-Allow-Origin: https://app.example.com

Rule 3 — Cookie Attributes: The cookie must be set with two attributes: SameSite=None and Secure. Without these two attributes, the browser will store the cookie but will never send it in cross-origin requests.

Sample Code in Node.js (Express)

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

const app = express();

app.use(cors({
  origin: 'https://app.example.com', // Exact frontend domain, no trailing slash
  credentials: true
}));

app.post('/login', (req, res) => {
  res.cookie('session_token', 'abc123', {
    httpOnly: true,   // Prevents JavaScript access to the cookie
    secure: true,     // Only sent over HTTPS
    sameSite: 'none', // Allows sending in Cross-Origin requests
    maxAge: 24 * 60 * 60 * 1000
  });
  res.json({ message: 'Login successful' });
});

Sample Code in PHP

<?php
// Specify the exact frontend domain, not *
header("Access-Control-Allow-Origin: https://app.example.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");

// Respond to Preflight request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

// Setting the cookie with required attributes
setcookie('session_token', 'abc123', [
    'expires'  => time() + 86400,
    'path'     => '/',
    'secure'   => true,      // Required
    'httponly' => true,
    'samesite' => 'None'     // Required for Cross-Origin
]);

Note: If you are using Laravel, set supports_credentials to true in config/cors.php and add the frontend domain to the allowed_origins array.

Step 2: Correct Client (Frontend) Configuration

Even with complete server configuration, the browser still will not send cookies unless you explicitly declare in the client side that this request is "with credentials".

Using Fetch API

fetch('https://api.example.com/user/profile', {
  method: 'GET',
  credentials: 'include'  // This line is the key to solving the issue
})
  .then(res => res.json())
  .then(data => console.log(data));

Using Axios

// For a specific request
axios.get('https://api.example.com/user/profile', {
  withCredentials: true
});

// Or globally for the entire project
axios.defaults.withCredentials = true;

Troubleshooting Checklist

If the issue persists after applying the above, check these items in order:

  • Are both sides on HTTPS? The Secure attribute means the cookie only works over encrypted connections. If your site is on HTTP, the browser will not accept the cookie. (Exception: development environment on localhost)
  • Is the Origin address exact? The Access-Control-Allow-Origin address must exactly match the URL you see in the browser. Even a difference in www or a trailing slash / will cause failure.
  • Is the OPTIONS request successful? In the Network tab of browser dev tools, check the Preflight request (with OPTIONS method). This request must be responded with status 200 or 204 and correct CORS headers.
  • Is the cookie stored? In the browser, go to DevTools ← Application ← Cookies and make sure the cookie is stored with Secure and SameSite=None attributes.
  • Do you have a proxy or intermediary firewall? Sometimes Cloudflare or web servers like Nginx rewrite headers. Check their configuration as well.

Summary

Sending cookies in cross-origin requests requires coordination of three factors: the server with Access-Control-Allow-Credentials: true and exact Origin, the cookie with SameSite=None; Secure attributes, and the client with credentials: 'include' or withCredentials: true. By following these three points, the issue will be completely resolved.


Reliable Infrastructure, Peace of Mind for Developers

Proper implementation of CORS and cookie management is only part of the story; the infrastructure on which your project runs also plays a decisive role in the stability and security of the service:

Radib Hosting — High-speed web hosting with full support for free SSL and standard header configuration; an ideal choice for hosting the frontend and backend of your projects.

Radib Virtual Server — If your project requires full access, dedicated resources, and freedom in web server configuration (Nginx/Apache), Radib virtual servers with powerful hardware and stable network are the best choice for professional APIs.

Radib Debugging and Security Services — If you are dealing with complex CORS errors, authentication issues, or security challenges, Radib's technical team, with deep experience in troubleshooting and securing web applications, is here to help you solve the problem from the root.

Was this answer helpful? 112 Users Found This Useful (112 Votes)