WordPress REST API erreur 401 : corriger l’authentification

Pour corriger une WordPress REST API erreur 401, vérifiez d’abord que la requête envoie bien les identifiants attendus, que l’utilisateur possède la permission requise et que le serveur ne retire pas l’en-tête Authorization. Dans WordPress, le code 401 signifie que l’API ne peut pas authentifier la demande. Testez ensuite la route avec curl, contrôlez les droits avec permission_callback, puis examinez les règles de sécurité, le cache et les cookies. Une erreur 401 ne se résout pas en désactivant au hasard toutes les extensions.

Cette erreur apparaît dans Gutenberg, une application React, un script Python, un site headless ou une intégration externe. Elle ressemble parfois à une erreur 403, mais le diagnostic n’est pas le même. Le serveur demande ici une identité reconnue, tandis que 403 indique généralement que l’identité est connue mais interdite.

Que signifie l’erreur 401 de la REST API WordPress

La REST API WordPress expose des routes sous /wp-json/. Certaines routes sont publiques, comme la lecture d’articles publiés. D’autres exigent une authentification, notamment la création d’un article, la modification d’un réglage ou l’accès à des données privées. Une réponse 401 est produite lorsque WordPress ou une couche située devant WordPress ne parvient pas à associer la requête à un utilisateur valide.

La cause peut être un mot de passe d’application absent, un nonce expiré, un cookie non transmis, une clé JWT incorrecte ou une configuration Basic Auth incomplète. Un proxy inverse peut aussi supprimer l’en-tête avant que PHP ne le reçoive. Il faut donc séparer les trois étapes suivantes : le client envoie-t-il le secret, le serveur le reçoit-il, WordPress accepte-t-il ce secret ?

Commencez par noter l’URL exacte, la méthode HTTP, les en-têtes, le statut et le corps de réponse. Une requête GET vers /wp-json/wp/v2/posts ne teste pas les mêmes droits qu’une requête POST vers la même collection. Ne partagez jamais un mot de passe ou un jeton dans une capture publique.

curl -i https://exemple.fr/wp-json/wp/v2/posts

# Afficher uniquement le statut et les en-têtes utiles
curl -sS -D - -o /tmp/reponse.json 
  https://exemple.fr/wp-json/wp/v2/posts 
  | grep -iE 'HTTP/|www-authenticate|x-wp|content-type'

Tester l’authentification avec un mot de passe d’application

Pour une intégration serveur à serveur, le mot de passe d’application WordPress est souvent le choix le plus simple. Il se crée dans le profil de l’utilisateur, possède un libellé identifiable et peut être révoqué indépendamment du mot de passe principal. Utilisez un compte aux droits minimaux, jamais le compte administrateur par défaut si un rôle éditeur suffit.

Le client doit envoyer une authentification Basic composée du nom d’utilisateur et du mot de passe d’application. Le mot de passe contient des espaces de présentation dans l’interface, mais il doit être nettoyé avant l’envoi. La commande curl ci-dessous laisse le programme construire l’en-tête. Ne placez pas ce secret dans un dépôt Git, une URL ou un fichier accessible par le navigateur.

export WP_USER='editeur-api'
export WP_APP_PASSWORD='xxxx xxxx xxxx xxxx xxxx xxxx'

curl -sS -u "$WP_USER:$WP_APP_PASSWORD" 
  -H 'Accept: application/json' 
  https://exemple.fr/wp-json/wp/v2/users/me

La route users/me est un bon test car elle indique si WordPress reconnaît réellement l’utilisateur. Si elle renvoie 401, le problème se situe avant les droits de la ressource. Si elle renvoie 200 mais que la création d’un article échoue, examinez alors le rôle, la capacité et la route utilisée.

Un mot de passe d’application peut être refusé si le site bloque l’authentification distante, si HTTPS n’est pas correctement configuré ou si une extension de sécurité filtre l’en-tête. Vérifiez aussi que l’utilisateur n’est pas suspendu et que l’horloge du serveur est correcte lorsque la solution utilise des jetons à durée limitée.

Vérifier l’en-tête Authorization derrière Apache ou Nginx

Un cas fréquent de WordPress REST API erreur 401 concerne l’en-tête Authorization qui disparaît entre le client et PHP. Apache, Nginx, un proxy CDN ou une règle de sécurité peut le retirer. WordPress reçoit alors une requête anonyme, même si votre client a bien construit le secret.

Sur Apache, la transmission peut nécessiter une règle adaptée à l’environnement d’hébergement. Sur Nginx avec PHP FPM, le paramètre fastcgi_param HTTP_AUTHORIZATION doit être présent lorsque la configuration ne le transmet pas déjà. Ne copiez pas une règle trouvée sur un forum sans vérifier la version du serveur et le gestionnaire PHP.

# Exemple Apache à adapter au serveur
SetEnvIf Authorization "(.+)" HTTP_AUTHORIZATION=$1

# Exemple Nginx dans le bloc PHP
fastcgi_param HTTP_AUTHORIZATION $http_authorization;

Après chaque changement, rechargez la configuration puis testez avec un endpoint temporaire qui affiche uniquement la présence de l’en-tête, jamais sa valeur. Sur un hébergement mutualisé, demandez au support si le proxy frontal transmet Authorization. Une règle WAF peut également produire un 401 avant même l’exécution de WordPress.

Si l’erreur n’apparaît que sur le domaine public et pas en local, comparez les en-têtes reçus, la terminaison TLS et les redirections. Une redirection HTTP vers HTTPS peut modifier le comportement du client ou empêcher la transmission de certains secrets. Utilisez directement l’URL finale en HTTPS.

Corriger les nonces WordPress dans JavaScript et Gutenberg

Dans le navigateur, WordPress utilise généralement un nonce REST envoyé dans X-WP-Nonce. Ce nonce ne remplace pas la session : il prouve que la requête vient d’une page WordPress où l’utilisateur est connecté. Un nonce expiré ou généré avec une mauvaise action peut provoquer une réponse 401, surtout après une longue session d’administration ou un cache HTML trop agressif.

Le script doit recevoir le nonce avec wp_localize_script ou wp_add_inline_script, puis le transmettre à chaque requête protégée. Ne mettez pas un nonce en dur dans le fichier JavaScript compilé. Il doit être généré pour l’utilisateur et la page actuels.

wp_localize_script(
    'mon-app',
    'MonApi',
    [
        'root'  => esc_url_raw( rest_url() ),
        'nonce' => wp_create_nonce( 'wp_rest' ),
    ]
);

fetch(`${MonApi.root}mon/v1/rapport`, {
    method: 'GET',
    headers: { 'X-WP-Nonce': MonApi.nonce }
});

Dans DevTools, contrôlez la requête réelle et non le code source initial. Vérifiez le nom exact de l’en-tête, la valeur générée et la réponse après reconnexion. Si une page est servie par un cache, elle peut contenir un nonce vieux de plusieurs heures. Les pages personnalisées de l’administration ne doivent pas être mises en cache comme des pages publiques.

Pour comprendre les différences entre nonce, cookie et authentification serveur, consultez notre guide avancé de la REST API WordPress. Il aide à choisir une méthode adaptée au contexte au lieu de mélanger les mécanismes.

Contrôler permission_callback et les droits de l’utilisateur

Une route personnalisée doit déclarer un permission_callback. Cette fonction décide si l’utilisateur authentifié peut utiliser la route. Elle ne doit pas se contenter de vérifier qu’un nom d’utilisateur existe. Utilisez une capacité précise comme edit_posts, manage_options ou une capacité métier créée pour votre extension.

add_action('rest_api_init', function () {
    register_rest_route('mon/v1', '/rapport', [
        'methods'  => WP_REST_Server::READABLE,
        'callback' => 'mon_lire_rapport',
        'permission_callback' => function () {
            return current_user_can('edit_posts');
        },
    ]);
});

Depuis les évolutions de WordPress, une route sans permission explicite déclenche un avertissement et peut être refusée selon son contexte. Retournez toujours une valeur booléenne ou une erreur WP_Error. Ne confondez pas l’absence de permission avec l’absence d’authentification. Pour une route publique, utilisez __return_true uniquement après avoir vérifié qu’aucune donnée privée n’est exposée.

Un utilisateur peut être correctement authentifié mais ne pas avoir le droit de publier dans une catégorie, de modifier un autre auteur ou d’accéder à une ressource privée. Comparez l’identité retournée par users/me avec les capacités attendues. Si vous modifiez le rôle, déconnectez et reconnectez la session pour éliminer un cookie obsolète.

Écarter les plugins de sécurité, le WAF et le cache

Les extensions de sécurité ajoutent parfois une authentification, un rate limiting ou une règle qui protège /wp-json/. Un WAF peut renvoyer 401 lorsqu’il voit un motif dans le corps JSON, un pays d’origine ou un en-tête considéré comme suspect. Comparez la réponse avec une requête minimale et vérifiez les journaux du serveur à la même seconde.

Le cache ne doit pas stocker une réponse 401 et la servir à tous les clients. Purgez les caches de page, de CDN et de proxy après une modification. Excluez les routes authentifiées, les requêtes POST et les réponses contenant des informations liées à l’utilisateur. Un cache mal réglé peut aussi conserver un HTML avec un nonce expiré.

Si la panne est plutôt un délai d’attente, consultez le guide consacré aux erreurs curl 28 et curl 7 de la REST API WordPress. Pour l’authentification, le durcissement et la limitation des tentatives, notre guide de sécurisation de l’API REST WordPress complète ce diagnostic.

# Tester sans cache applicatif
curl -sS -D - -o /tmp/api.json 
  -H 'Cache-Control: no-cache' 
  -H 'Accept: application/json' 
  https://exemple.fr/wp-json/wp/v2/users/me

# Inspecter le statut et le type de réponse
head -20 /tmp/api.json

Diagnostiquer une intégration Python ou Node.js

Les bibliothèques clientes peuvent masquer l’en-tête ou encoder deux fois les identifiants. Commencez par reproduire la même requête avec curl, puis comparez la méthode, l’URL, le corps et les en-têtes. Ne loguez pas le secret complet. Utilisez une empreinte ou remplacez sa valeur par des astérisques avant d’écrire les journaux.

import os
import requests

url = 'https://exemple.fr/wp-json/wp/v2/users/me'
auth = (os.environ['WP_USER'], os.environ['WP_APP_PASSWORD'])
r = requests.get(url, auth=auth, timeout=15)
print(r.status_code, r.headers.get('content-type'))
print(r.json() if r.status_code == 200 else r.text[:300])

Dans Node.js, fournissez l’en-tête avec la forme attendue par l’API et vérifiez que la variable d’environnement n’est pas vide. Une variable absente peut produire un en-tête valide en apparence mais inutilisable. Ajoutez un contrôle de démarrage qui arrête l’application si les paramètres essentiels manquent.

Pour une application mobile ou un service public, ne distribuez jamais un mot de passe d’application dans le code client. Le secret doit rester côté serveur. Le client appelle votre backend, qui applique ses propres règles et contacte WordPress avec une identité limitée. Cette séparation réduit l’impact d’une fuite.

Checklist finale pour supprimer l’erreur 401

La résolution durable tient dans une séquence courte. Testez d’abord users/me, puis la route métier. Vérifiez ensuite l’arrivée de l’en-tête, les droits, les nonces et les règles du proxy. Enfin, purgez les caches et répétez le test depuis le même environnement que l’utilisateur réel.

# Checklist shell indicative
curl -sS -o /dev/null -w '%{{http_code}}n' 
  -u "$WP_USER:$WP_APP_PASSWORD" 
  https://exemple.fr/wp-json/wp/v2/users/me

# Vérifier une route publique séparément
curl -sS -o /dev/null -w '%{{http_code}}n' 
  https://exemple.fr/wp-json/wp/v2/posts

Conservez une trace de la cause et de la correction. Si l’erreur revient, vous saurez si elle suit une expiration de nonce, un déploiement, une modification du WAF ou une rotation de secret. Révoquez les identifiants inutilisés, activez HTTPS partout et limitez les comptes de service aux capacités réellement nécessaires.

FAQ sur l’erreur 401 de la REST API WordPress

Pourquoi la REST API WordPress renvoie-t-elle 401 ?

La REST API WordPress renvoie 401 lorsqu’elle ne reconnaît pas l’identité de la requête. Les causes courantes sont un mot de passe d’application incorrect, un nonce expiré, un cookie absent ou un en-tête Authorization supprimé par le proxy.

Quelle est la différence entre erreur 401 et erreur 403 dans WordPress ?

L’erreur 401 indique que l’authentification manque ou échoue. L’erreur 403 signifie généralement que l’utilisateur est reconnu mais n’a pas la permission d’utiliser la ressource demandée.

Comment tester une authentification WordPress avec curl ?

Appelez /wp-json/wp/v2/users/me avec curl -u utilisateur:mot-de-passe-application sur une connexion HTTPS. Une réponse 200 confirme l’identité, tandis qu’une réponse 401 oriente vers le secret, l’en-tête ou le proxy.

Pourquoi X-WP-Nonce provoque-t-il une erreur 401 ?

Un nonce WordPress peut être expiré, généré pour une autre action ou absent de la requête JavaScript. Rechargez une page d’administration fraîche, régénérez le nonce côté PHP et vérifiez la requête réelle dans les outils du navigateur.

Faut-il utiliser un plugin pour corriger une erreur 401 ?

Non. Le diagnostic commence avec les outils natifs de WordPress, curl, les journaux et la configuration du serveur. Un plugin peut ajouter une authentification, mais il peut aussi être la source du conflit et doit être testé avec méthode.

Sources utiles : documentation WordPress sur l’authentification REST, routes et endpoints WordPress, création d’endpoints personnalisés, référence wp_create_nonce, référence current_user_can, documentation curl sur les cookies HTTP.

G
WP Admin Lab

Architecte web full-stack. WordPress, performance, data et sécurité. Notes de terrain, tests reproductibles et retours d'expérience.