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.
# 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ésIl 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 :
<?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.
<?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 :
// 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.