Skip to content

Configurazione CORS e Cookie per Chrome

Problema

Chrome non invia cookie nelle richieste AJAX cross-origin, mentre Firefox funziona.

Causa

Chrome applica politiche di sicurezza più restrittive per i cookie di terze parti (third-party cookies) rispetto a Firefox. Per far funzionare credentials: "include", sono necessarie configurazioni specifiche sia lato server che lato client.

Soluzione

1. Lato Server PHP (Erp_auth.php o middleware CORS)

Il server deve inviare gli header CORS corretti:

php
// ❌ NON FUNZIONA con credentials
header('Access-Control-Allow-Origin: *');

// ✅ FUNZIONA: origin specifico
$allowed_origins = [
    'http://localhost:5173',  // dev
    'https://app.daisy.local', // prod
];

$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowed_origins)) {
    header("Access-Control-Allow-Origin: $origin");
}

// ✅ OBBLIGATORIO per credentials
header('Access-Control-Allow-Credentials: true');

// ✅ Metodi e header permessi
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Daisy-Erp');

// ✅ Gestione preflight OPTIONS
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

I cookie devono essere impostati con attributi specifici:

php
// ❌ NON FUNZIONA su Chrome cross-origin
setcookie('session_id', $value, [
    'path' => '/',
    'httponly' => true,
]);

// ✅ FUNZIONA su Chrome
setcookie('session_id', $value, [
    'path' => '/',
    'httponly' => true,
    'secure' => true,      // Richiede HTTPS
    'samesite' => 'None',  // Permette cross-origin
]);

⚠️ IMPORTANTE: Secure richiede HTTPS. Per sviluppo locale usa:

  • https://api.local.daisy (con certificato self-signed)
  • Oppure disabilita temporaneamente le restrizioni Chrome (non raccomandato per prod)

3. Lato Client (già configurato)

typescript
// app/lib/api.ts
const response = await fetch(`${baseUrl}${endpoint}`, {
    credentials: "include", // ✅ Include cookies
    headers: {
        "Content-Type": "application/json",
        "Daisy-Erp": "frontend",
    },
});

Verifica Configurazione

1. Controlla Headers di Risposta (Chrome DevTools)

Apri DevTools → Network → seleziona una richiesta API:

Response Headers:
✅ Access-Control-Allow-Origin: http://localhost:5173
✅ Access-Control-Allow-Credentials: true
❌ Access-Control-Allow-Origin: * (NON funziona)

Apri DevTools → Application → Cookies:

✅ SameSite: None
✅ Secure: true
❌ SameSite: Lax/Strict (non inviato cross-origin)

3. Test nel Console

javascript
fetch('https://api.local.daisy/erp/erp_auth/check-auth/', {
    credentials: 'include'
})
.then(r => r.json())
.then(console.log);

Se vedi i cookie nella tab "Cookies" della richiesta in Network, funziona! ✅

Esempio Completo PHP

php
<?php
// cors.php - Middleware CORS centralizzato

class CorsMiddleware {
    private $allowed_origins = [
        'http://localhost:5173',
        'https://app.daisy.local',
    ];

    public function handle() {
        $origin = $_SERVER['HTTP_ORIGIN'] ?? '';

        if (in_array($origin, $this->allowed_origins)) {
            header("Access-Control-Allow-Origin: $origin");
            header('Access-Control-Allow-Credentials: true');
            header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
            header('Access-Control-Allow-Headers: Content-Type, Daisy-Erp');
        }

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

    public function setCookie($name, $value, $options = []) {
        $defaults = [
            'expires' => time() + 3600,
            'path' => '/',
            'httponly' => true,
            'secure' => true,    // ✅ HTTPS required
            'samesite' => 'None', // ✅ Cross-origin
        ];

        setcookie($name, $value, array_merge($defaults, $options));
    }
}

// In Erp_auth.php
$cors = new CorsMiddleware();
$cors->handle();

// Quando imposti il cookie di sessione
$cors->setCookie('session_id', $session_id);

Troubleshooting

  1. Verifica che sia HTTPS: Secure richiede HTTPS, HTTP non funziona
  2. Cancella cache e cookie: Settings → Privacy → Clear browsing data
  3. Disabilita estensioni: Alcune estensioni bloccano third-party cookies
  4. Controlla flag Chrome: chrome://flags/#same-site-by-default-cookies

Firefox funziona, Safari no

Safari ha restrizioni ancora più severe. Assicurati che:

  • Origin sia nella lista allowed_origins
  • Cookie abbiano SameSite=None; Secure
  • Server invii Access-Control-Allow-Credentials: true

Errore "Blocked by CORS policy"

Controlla che:

  • Access-Control-Allow-Origin sia l'origin specifico (non *)
  • Access-Control-Allow-Credentials: true sia presente
  • Server gestisca preflight OPTIONS correttamente

Riferimenti

Documentazione Elerama Frontend