# rest_authorization_required_code : renvoyer 401 plutôt que 403 quand c’est juste

> Un visiteur non connecté et un visiteur connecté mais non autorisé ne méritent pas le même code HTTP. Ce filtre natif permet enfin de les distinguer.

- Auteur : WordPress Développement
- Publié le : 2023-03-09
- Mis à jour le : 2023-03-09
- Catégorie : Astuces
- URL : https://www.wpmoderne.fr/tips/rest-authorization-required-code-401-403/

## L’essentiel

- 401 signifie non identifié, 403 signifie identifié mais refusé
- Le filtre rest_authorization_required_code choisit lequel renvoyer
- is_user_logged_in() suffit à trancher dans permission_callback

Pourquoi un endpoint REST protégé renvoie-t-il systématiquement 403, même quand le visiteur n'est tout simplement pas connecté ? C'est la question qui revient dès qu'on regarde de près le comportement par défaut de l'API REST de WordPress sur les routes qui exigent une authentification.

La nuance a pourtant un sens précis dans la spécification HTTP : 401 (*Unauthorized*) signifie « je ne sais pas qui vous êtes », tandis que 403 (*Forbidden*) signifie « je sais qui vous êtes, et vous n'avez pas le droit ». Confondre les deux complique le travail de tout client qui essaie de réagir intelligemment à une erreur, par exemple en proposant un écran de connexion plutôt qu'un simple message bloquant.

## Le comportement par défaut de l'API REST

Par défaut, quand un `permission_callback` renvoie `false` ou un objet `WP_Error` sans code HTTP explicite, WordPress applique une règle unique : il renvoie 401 si l'utilisateur n'est pas connecté, et 403 s'il l'est. Cette logique est centralisée dans le filtre `rest_authorization_required_code`, disponible dans `WP_REST_Server`.

Le souci vient rarement du cœur lui-même, mais de la façon dont les développeurs codent leurs `permission_callback` : beaucoup renvoient un simple `false` booléen ou une erreur générique sans distinguer les deux cas, ce qui aplatit la nuance avant même que le filtre n'entre en jeu.

## Écrire un permission_callback qui distingue les deux cas

> L'essentiel à retenir : 401 signifie non identifié, 403 signifie identifié mais refusé ; Le filtre rest_authorization_required_code choisit lequel renvoyer ; is_user_logged_in() suffit à trancher dans permission_callback

La bonne pratique consiste à vérifier explicitement l'état de connexion avant de statuer sur l'autorisation :

```
register_rest_route( 'boutique/v1', '/factures/(?P<id>\d+)', array(
    'methods'             => 'GET',
    'callback'            => 'boutique_get_facture',
    'permission_callback' => function ( $request ) {
        if ( ! is_user_logged_in() ) {
            return new WP_Error(
                'rest_not_logged_in',
                'Vous devez être connecté pour consulter cette facture.',
                array( 'status' => 401 )
            );
        }

        if ( ! current_user_can( 'read_facture', $request['id'] ) ) {
            return new WP_Error(
                'rest_forbidden',
                "Vous n'avez pas accès à cette facture.",
                array( 'status' => 403 )
            );
        }

        return true;
    },
) );
```

En précisant le statut directement dans les données de l'erreur, on court-circuite la logique par défaut du filtre pour ce cas précis : WordPress respecte le statut explicitement fourni plutôt que d'appliquer sa règle générique.

## Utiliser le filtre pour un comportement global

Quand la distinction doit s'appliquer à toutes les routes d'un site, plutôt que de retoucher chaque `permission_callback` une par une, on peut ajuster directement le filtre :

```
add_filter( 'rest_authorization_required_code', function ( $code ) {
    if ( ! is_user_logged_in() ) {
        return 401;
    }

    return 403;
} );
```

Ce filtre reçoit en argument le code par défaut calculé par WordPress et permet de le remplacer selon un contexte plus large, par exemple en tenant compte d'un rôle ou d'une capacité spécifique au projet.

## Ce que change la distinction pour le client

- Un client JavaScript peut rediriger vers l'écran de connexion sur un 401, sans afficher de message d'erreur alarmant.
- Un 403 peut déclencher un message explicite du type « contactez votre administrateur », plus adapté qu'une simple invitation à se reconnecter.
- Les outils de supervision et les journaux d'accès distinguent mieux les tentatives d'intrusion des simples sessions expirées.

Sur une application qui consomme l'API REST depuis un frontal découplé, cette distinction évite des heures de débogage côté client, là où un développeur cherche pourquoi un utilisateur pourtant connecté se retrouve renvoyé vers la page de connexion.

## Le cas des routes publiques avec restriction partielle

Un cas plus subtil concerne les routes accessibles à tous mais dont certains champs sont restreints selon les droits. Dans ce contexte, on ne renvoie jamais une erreur globale : on filtre plutôt la réponse elle-même, en retirant les champs sensibles pour les visiteurs non autorisés plutôt qu'en bloquant toute la requête. La logique 401/403 ne s'applique alors qu'aux routes réellement fermées.

> Sur une API destinée à être consommée par un client tiers, documenter explicitement quel code HTTP correspond à quelle situation fait gagner un temps précieux à l'équipe qui l'intègre.

## En résumé

Le réflexe à adopter est simple : vérifier `is_user_logged_in()` avant de statuer sur les permissions, et laisser le filtre `rest_authorization_required_code` gérer les cas non explicités. Cette petite discipline suffit à transformer une API REST approximative en une API dont chaque code HTTP raconte fidèlement ce qui s'est passé.
