BaliseTonSite

Authentification cross-domain

Connecter un utilisateur quand le front et le back sont sur 2 domaines différents.

7.1Le problème cross-domain

Quand l'utilisateur se connecte via l'API WordPress, le serveur envoie un cookie d'authentification. Mais par défaut, ce cookie est rejeté par le navigateur car il vient d'un domaine différent.

Bashbash
# Le navigateur est sur :     www.monsite.fr
# L'API WordPress est sur :  cms.monsite.fr

# Le cookie 'wordpress_logged_in_xxx' vient de cms.monsite.fr
# Le navigateur le refuse : "Cookie tiers, domaine différent"

# Solution : configurer les cookies pour qu'ils soient acceptés

Il y a 3 pièces du puzzle à assembler :

Cookies WordPress

SameSite=None, Secure, domaine partagé

CORS

Autoriser les requêtes cross-origin avec credentials

Fetch credentials

Envoyer les cookies avec chaque requête

7.2Configurer les cookies WordPress

WordPress utilise des cookies natifs pour l'authentification. Pour qu'ils fonctionnent en cross-domain, il faut modifier leur configuration :

PHPphp
<?php
// wp-config.php ou plugin custom

// Domaine partagé : le cookie est valide sur *.monsite.fr
define('COOKIE_DOMAIN', '.monsite.fr');

// Force les cookies en HTTPS (obligatoire pour SameSite=None)
define('FORCE_SSL_ADMIN', true);

// Dans un plugin : modifier les attributs des cookies
add_action('set_auth_cookie', function() {
    // Les cookies d'auth WordPress seront configurés avec :
    // SameSite=None  -> accepté en cross-domain
    // Secure=true    -> uniquement en HTTPS
    // HttpOnly=true  -> invisible au JavaScript (sécurité XSS)
}, 10, 0);

// Modifier les headers Set-Cookie
add_action('send_headers', function() {
    if (!headers_sent()) {
        header('Set-Cookie: SameSite=None; Secure', false);
    }
});

7.3Configurer CORS sur WordPress

CORS (Cross-Origin Resource Sharing) : le mécanisme qui autorise un site à appeler l'API d'un autre domaine.

PHPphp
<?php
add_action('rest_api_init', function() {
    // Supprime les headers CORS par défaut de WordPress
    remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');

    // Ajoute nos propres headers CORS
    add_filter('rest_pre_serve_request', function($served) {
        $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
        $allowed_origins = [
            'https://www.monsite.fr',
            'http://localhost:3000',   // Développement
            'http://localhost:3001',   // Développement (Next.js)
        ];

        if (in_array($origin, $allowed_origins, true)) {
            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, Authorization');
        }

        return $served;
    });
});

// Gérer les requêtes OPTIONS (preflight)
add_action('init', function() {
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
        $allowed_origins = [
            'https://www.monsite.fr',
            'http://localhost:3000',
            'http://localhost:3001',
        ];

        if (in_array($origin, $allowed_origins, true)) {
            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, Authorization');
            header('Access-Control-Max-Age: 86400');
        }
        exit(0);
    }
});

7.4Côté Next.js : envoyer les cookies

Côté front, chaque appel API doit inclure credentials: 'include' pour que le navigateur envoie et reçoive les cookies :

TypeScripttypescript
// OBLIGATOIRE : credentials include pour les cookies
const response = await fetch('/api/wp-json/bts/v1/me', {
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
})

// Login
const login = await fetch('/api/wp-json/bts/v1/login', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: email,
    password: password,
  }),
})

// Si le login réussit, le cookie wordpress_logged_in_xxx
// est automatiquement stocké par le navigateur.
// Tous les appels suivants avec credentials: 'include'
// l'enverront automatiquement.

7.5Les pièges classiques

Slash final dans l'URL

WordPress redirige /wp-json/bts/v1/login/ vers /wp-json/bts/v1/login avec un 307. Cette redirection perd les cookies et les headers CORS. Toujours sans slash final.

Mixed content HTTP/HTTPS

Si ton front est en HTTPS et ton WordPress en HTTP, les cookies Secure ne seront jamais envoyés. Les deux doivent être en HTTPS.

Oublier credentials: 'include'

Sans ce paramètre, fetch n'envoie pas les cookies. Ton endpoint /me retournera "non connecté" même si l'utilisateur l'est.

Verifie tes acquis

5 questions pour valider ce chapitre

1. Pourquoi les cookies WordPress sont rejetes par defaut en cross-domain ?

Valide et sauvegarde ce chapitre

Ne perds pas le fil de ton apprentissage. Chaque QCM terminé sauvegarde ton score. Crée ton profil gratuitement pour débloquer toutes les évaluations du site et retrouver tes résultats plus tard.

Commencer l'aventure
Déjà membre ?Connecte-toi