Un connecteur doit lire les commandes d'une boutique WooCommerce pour les envoyer au logiciel de gestion, et le premier appel répond 401 avec woocommerce_rest_cannot_view : "Sorry, you cannot list resources.". Ce message ne veut pas dire "mauvaise clé" : il signifie que WooCommerce n'a vu aucune clé, parce qu'elle n'a pas été transmise, qu'elle a été ignorée (appel en HTTP) ou que l'en-tête Authorization s'est perdu entre Apache et PHP. Nous avons reproduit chaque cas sur une boutique de test, derrière Apache et PHP-FPM.
Que veut dire exactement l'erreur reçue ?
Le code et le statut renvoyés indiquent la piste à suivre. Voici ce que nous avons obtenu sur GET /wp-json/wc/v3/products :
| Situation | Réponse |
|---|---|
| Aucune authentification | 401 woocommerce_rest_cannot_view |
| Basic Auth sur une adresse en HTTP | 401 woocommerce_rest_cannot_view |
HTTPS, en-tête Authorization perdu côté serveur |
401 woocommerce_rest_cannot_view |
| Mauvais secret | 401 woocommerce_rest_authentication_error : "Consumer secret is invalid." |
Clé en lecture seule, requête POST |
401 woocommerce_rest_authentication_error : "The API key provided does not have write permissions." |
| Clé rattachée à un simple abonné | 403 woocommerce_rest_cannot_view |
Un 401 avec woocommerce_rest_cannot_view veut donc dire : requête vue comme anonyme.
La boutique est-elle appelée en HTTPS ?
C'est la première cause. La documentation de l'API REST de WooCommerce prévoit deux modes :
- En HTTPS : "You may use HTTP Basic Auth by providing the REST API Consumer Key as the username and the REST API Consumer Secret as the password."
- En HTTP : "You must use OAuth 1.0a "one-legged" authentication to ensure REST API credentials cannot be intercepted by an attacker."
Le code de WooCommerce ne tente l'authentification Basic que si is_ssl() est vrai. En HTTP, la même clé envoyée en Basic, ou dans l'adresse, est ignorée : 401. Une requête signée en OAuth 1.0a sur la même adresse HTTP a, elle, répondu 200. L'exemple de la documentation, à appeler en HTTPS :
curl https://www.example.com/wp-json/wc/v3/orders \ -u consumer_key:consumer_secret
Cas fréquent : le HTTPS est géré par un proxy ou un équilibreur de charge, et WordPress reçoit la requête en HTTP. is_ssl() est alors faux, et la clé est ignorée. Dans notre test, une requête Basic avec l'en-tête X-Forwarded-Proto: https a répondu 401 avec un wp-config.php standard, puis 200 après l'ajout de ces lignes (présentes d'office dans l'image Docker officielle de WordPress) :
<?php // wp-config.php, avant la ligne "That's all, stop editing!" if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) { $_SERVER['HTTPS'] = 'on'; }
La documentation de WordPress donne ce réglage pour un site derrière un proxy qui gère le HTTPS, "assuming you have properly configured the reverse proxy to set that header" : à n'ajouter que si c'est bien le proxy qui fixe cet en-tête.
L'en-tête Authorization arrive-t-il jusqu'à PHP ?
Deuxième cause, sur les serveurs Apache où PHP tourne à part (PHP-FPM, CGI). La documentation d'Apache explique que les en-têtes d'autorisation sont normalement cachés aux scripts : "Normally these HTTP headers are hidden from scripts." C'est le cas pour mod_proxy_fcgi, qui relie Apache à PHP-FPM.
WordPress contourne ce point dans le bloc qu'il écrit lui-même dans .htaccess (généré ici avec wp rewrite structure "/%postname%/" --hard) :
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
En HTTPS, avec ce bloc, l'appel Basic répond 200. Sans la ligne E=HTTP_AUTHORIZATION (ancien .htaccess recopié, fichier réécrit par une extension ou à la main), il répond 401 woocommerce_rest_cannot_view. Deux autres corrections ont fonctionné, à placer en tête du .htaccess :
# Option 1 : Apache 2.4.13 et plus CGIPassAuth On # Option 2 : recopier l'en-tête dans une variable SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
La documentation de WooCommerce évoque le même problème : si un message "Consumer key is missing" apparaît en HTTPS, "you have a server issue".
Et si l'on ne peut pas modifier le serveur ?
WooCommerce accepte les clés dans l'adresse, en HTTPS uniquement : "you may provide the consumer key/secret as query string parameters instead."
curl "https://www.example.com/wp-json/wc/v3/orders?consumer_key=123&consumer_secret=abc"
Les guillemets évitent que le terminal interprète le &. Dans notre test, cette forme a fonctionné même quand l'en-tête Authorization était perdu. Contrepartie : la clé apparaît dans l'adresse, donc dans les journaux du serveur. À réserver aux cas où la correction côté serveur est impossible.
La clé a-t-elle les bons droits ?
Deux réglages de la clé, créée dans WooCommerce > Settings > Advanced > REST API (chemin de la documentation, interface en anglais) :
- Les droits : lecture, écriture ou lecture/écriture. Une clé en lecture seule lit sans problème, mais un
POSTrépond 401 avec un message clair sur les droits d'écriture. - L'utilisateur : la documentation précise que l'usage de la clé "will conform to that user's WordPress roles and capabilities". Une clé rattachée à un abonné renvoie 403. Si l'utilisateur est supprimé, "the API key will cease to function".
Pour un connecteur, mieux vaut donc un utilisateur dédié : la clé ne dépend pas du compte d'un collaborateur qui pourrait être supprimé. Relier une boutique au logiciel de gestion (commandes, stocks, clients, factures) est une grande part de notre travail sur les connecteurs entre logiciels, souvent avec des tâches automatisées derrière. Une question sur votre boutique ? Contactez-nous.
- 401
woocommerce_rest_cannot_view= requête vue comme anonyme, pas une clé fausse (qui donne "Consumer secret is invalid."). - Basic Auth seulement en HTTPS ; derrière un proxy, WordPress doit savoir que la requête est en HTTPS.
- Apache + PHP-FPM : garder
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}], ouCGIPassAuth On. - Clé en lecture/écriture si le connecteur écrit, rattachée à un utilisateur dédié qui a les bons droits.
Testé avec WordPress 7.1.3, WooCommerce 11.2.1, PHP-FPM 8.3.35, Apache 2.4.69 et WP-CLI 2.12.0 (Docker).
Questions fréquentes
Quelle différence entre une erreur 401 et 403 sur l'API WooCommerce ?
Dans nos tests, un 401 woocommerce_rest_cannot_view correspond à une requête vue comme anonyme, alors qu'un 403 avec le même code arrive quand la clé est reconnue mais que son utilisateur n'a pas les droits nécessaires (un abonné, par exemple).
Peut-on utiliser l'API WooCommerce sans HTTPS ?
Oui, avec l'authentification OAuth 1.0a "one-legged", où chaque requête est signée avec le secret. Un appel en Basic Auth ou avec la clé dans l'adresse est ignoré en HTTP.
Faut-il des permaliens particuliers pour l'API REST ?
Oui, la documentation de WooCommerce demande des permaliens "jolis" (Settings > Permalinks) pour les adresses /wp-json/ : les permaliens par défaut ne fonctionnent pas.
Une clé en lecture suffit-elle pour un connecteur ?
Pour lire commandes, produits et clients, oui. Dès que le connecteur doit écrire (mettre à jour un stock, changer le statut d'une commande), il faut une clé en lecture/écriture, sinon WooCommerce répond que la clé n'a pas les droits d'écriture.