← API REST : concevoir, mûrir, documenter

Authentification et sécurité : API keys, JWT, OAuth2

≈ 25 minutes · Jalon M5 · Prérequis : Concevoir une API propre : pagination, filtres, versioning, erreurs

Le gain du jour : distinguer authentification et autorisation, connaître les trois mécanismes les plus courants pour sécuriser une API REST, et comprendre pourquoi HTTP « sans état » impose de rejouer une preuve d’identité à chaque requête.

Authentification vs autorisation : deux questions différentes

On les code souvent ensemble, mais elles répondent à des questions distinctes — c’est d’ailleurs exactement la nuance entre 401 Unauthorized (authentification manquante ou invalide) et 403 Forbidden (identité connue, mais droits insuffisants) vue en leçon 2.

Rappel : pourquoi il faut prouver son identité à chaque requête

Leçon 1 : une API REST est sans état — le serveur ne garde aucune mémoire d’une requête à l’autre. Il ne peut donc pas se souvenir « ce client s’est connecté il y a 2 minutes ». Chaque requête doit apporter sa propre preuve d’identité, généralement dans l’en-tête Authorization.

Mécanisme 1 : les clés d’API (API keys)

Le plus simple : le serveur génère une chaîne secrète unique par client (souvent par application, pas par utilisateur final), que le client renvoie à chaque requête.

GET /orders
Authorization: Bearer sk_live_4f8a2c9b3e1d...

Mécanisme 2 : JWT — un jeton auto-porteur

Un JWT (JSON Web Token, RFC 7519) encode des informations directement dans le jeton lui-même, signées cryptographiquement par le serveur. Trois parties séparées par des points, encodées en Base64 :

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0MiIsInJvbGUiOiJhZG1pbiJ9.4f8a2c9b...
   └── en-tête (algo) ─┘  └────── charge utile (payload) ──────┘  └ signature ┘

La charge utile décodée (elle est lisible, pas chiffrée — ne jamais y mettre de secret) ressemble à :

{"sub": "42", "role": "admin", "exp": 1893456000}

Le serveur vérifie la signature (pas de base de données à consulter) pour confirmer que le jeton n’a pas été altéré, et regarde exp (date d’expiration) pour le rejeter s’il est trop vieux.

Le vrai avantage d’un JWT : pas de consultation de base de données

Avec une session classique, chaque requête oblige le serveur à consulter une base ou un cache (« ce jeton de session existe-t-il encore ? »). Un JWT signé se vérifie mathématiquement, sans aller interroger quoi que ce soit — cohérent avec la contrainte stateless de REST, et beaucoup plus rapide à grande échelle.

Le vrai piège : la révocation

Puisqu’un JWT se vérifie sans consulter de base de données, révoquer un jeton avant son expiration naturelle est difficile — le serveur n’a par construction aucune liste centrale à jour. En pratique : jetons de courte durée de vie (quelques minutes) + un refresh token séparé, à durée de vie plus longue, stocké et révocable côté serveur.

Mécanisme 3 : OAuth2 — déléguer l’authentification à un tiers

OAuth2 (RFC 6749) répond à un problème différent : « Se connecter avec Google » sur un site tiers, sans jamais lui donner ton mot de passe Google. Le principe : le fournisseur d’identité (Google, GitHub…) délivre un jeton d’accès à l’application tierce, avec des permissions limitées (scopes — « lire mon email », pas « publier en mon nom »).

1. L'utilisateur clique « Se connecter avec Google » sur le site tiers.
2. Il est redirigé vers Google, se connecte, et approuve les permissions demandées.
3. Google redirige vers le site tiers avec un code d'autorisation temporaire.
4. Le site tiers échange ce code contre un jeton d'accès (en coulisses, serveur à serveur).
5. Le site tiers utilise ce jeton pour appeler l'API Google (ex. lire le profil).
OAuth2 authentifie l’accès, pas directement l’utilisateur

OAuth2 résout l’autorisation déléguée (donner un accès limité à une application tierce), pas l’authentification de l’utilisateur au sens strict. C’est pour cela qu’existe OIDC (OpenID Connect), une couche construite par-dessus OAuth2 spécifiquement pour répondre à « qui est cet utilisateur ? » de façon standardisée (jeton d’identité, en plus du jeton d’accès).

Vérifie ta compréhension

1. Quelle est la différence entre authentification et autorisation ?

2. Pourquoi un JWT peut-il être vérifié sans consulter une base de données ?

3. Quel problème résout spécifiquement OAuth2 ?

À toi de jouer

  1. Décode à la main (sans outil, juste en Base64) l’en-tête et la charge utile d’un JWT d’exemple trouvé sur jwt.io — observe qu’aucune information n’y est chiffrée, seulement signée.

  2. Pour une API que tu conçois (fictive ou réelle), décide : accès machine à machine (clé d’API), utilisateurs humains avec mot de passe (JWT + refresh token), ou connexion déléguée à un tiers (OAuth2) ? Justifie ton choix en une phrase.

Pour aller plus loin

📖 Sources principales : RFC 7519 — JSON Web Token (JWT), RFC 6749 — The OAuth 2.0 Authorization Framework, et jwt.io pour décoder et expérimenter avec de vrais jetons.

🗂 Fiche de référence associée : Verbes, codes, en-têtes — antisèche.