12 - L'authentification HTTP : prouver qui tu es
Ce que tu vas apprendre
- Le fonctionnement des headers WWW-Authenticate et Authorization
- Basic auth et pourquoi il faut HTTPS
- Les tokens Bearer et JWT
- Les clés API et ou les placer
- La différence réelle entre 401 et 403
- Digest auth et Proxy-Authorization
Prerequisites
Tu fais une requête vers une ressource protégée. Le serveur ne te connaît pas. Il répond avec un 401 et te dit comment t'authentifier. Tu renvoies ta requête avec tes identifiants. Le serveur vérifié et te laisse passer, ou pas.
C'est le schema fondamental de l'authentification HTTP. Deux headers font tout le travail : WWW-Authenticate dans la réponse du serveur, et Authorization dans la requête du client.
Le dialogue d'authentification
Client Serveur
|--- GET /secret -------------->|
|<-- 401 Unauthorized ----------|
| WWW-Authenticate: Basic |
| |
|--- GET /secret -------------->|
| Authorization: Basic xyz |
|<-- 200 OK --------------------|
Le serveur annonce le schema d'authentification qu'il attend via WWW-Authenticate. Le client répond avec le header Authorization contenant ses identifiants encodes selon le schema demande.
Basic auth : simple et dangereux
L'authentification Basic encode le login et le mot de passe en Base64 :
Authorization: Basic bmljb2xhczpzZWNyZXQxMjM=
Decodons :
echo "bmljb2xhczpzZWNyZXQxMjM=" | base64 -d
# nicolas:secret123
C'est tout. Le mot de passe est en clair, juste encode (pas chiffre) en Base64. N'importe qui sur le réseau peut le lire. Sans HTTPS, Basic auth equivaut a crier son mot de passe dans la rue.
Avec HTTPS, c'est acceptable pour des cas simples. Beaucoup de registres Docker, d'API internes et d'outils d'administration utilisent Basic auth sur HTTPS. Le navigateur affiche meme une popup native pour saisir login et mot de passe quand il recoit un WWW-Authenticate: Basic.
Le problème : le navigateur renvoie les identifiants a chaque requête. Il n'y a pas de mecanisme de deconnexion propre. La seule facon de "se deconnecter" est de fermer le navigateur ou d'attendre que le cache d'identifiants expire.
Bearer tokens : le standard moderne
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Un token Bearer est un jeton opaque ou structure que le client presente a chaque requête. Le serveur vérifié le token au lieu de vérifier un mot de passe.
Le cas le plus courant : les JWT (JSON Web Tokens). Un JWT contient trois parties separees par des points :
header.payload.signature
Le header indique l'algorithme de signature. Le payload contient les donnees (identifiant utilisateur, rôles, date d'expiration). La signature garantit que personne n'a modifie le contenu.
json{
"sub": "user-42",
"role": "admin",
"exp": 1743292800
}
L'avantage du JWT : le serveur n'a pas besoin de stocker de session. Il vérifié la signature avec sa clé secrete et fait confiance au contenu. C'est stateless.
L'inconvenient : tu ne peux pas revoquer un JWT avant son expiration. Si un token fuite, il reste valide jusqu'a la date exp. Les solutions (blacklist, tokens a courte duree + refresh token) ajoutent de la complexité.
J'ai deja vu des JWT avec des durees d'expiration d'un an. Autant donner la clé de chez toi a un inconnu. Un JWT devrait expirer en 15 minutes a une heure maximum, avec un refresh token pour le renouveler.
Cles API : header vs query string
Les clés API sont des tokens statiques qui identifient un client :
# Dans un header
X-API-Key: ak_live_7f3a2b1c9d8e
Authorization: Bearer ak_live_7f3a2b1c9d8e
# Dans la query string
GET /api/data?api_key=ak_live_7f3a2b1c9d8e
Le header est toujours préférable. La query string se retrouve dans les logs du serveur, dans l'historique du navigateur, dans les headers Referer. C'est un vecteur de fuite classique.
Certaines API (Google Maps, par exemple) utilisent la query string par commodite pour les appels cote client. Mais ces clés sont restreintes par domaine et ne donnent acces qu'a des fonctionnalités limitees.
Sur paltemps.fr, les clés API sont toujours dans un header. Les logs ne contiennent jamais de secret.
Digest auth : le compromis oublie
Digest auth resout le problème de Basic auth sans HTTPS. Au lieu d'envoyer le mot de passe, le client envoie un hash :
WWW-Authenticate: Digest realm="api", nonce="abc123", qop="auth"
Le client calcule :
HA1 = MD5(username:realm:password)
HA2 = MD5(method:uri)
response = MD5(HA1:nonce:nc:cnonce:qop:HA2)
Le mot de passe ne transite jamais sur le réseau. Le nonce (nombre utilise une seule fois) empeche les attaques par rejeu.
En pratique, Digest auth est mort. MD5 est considéré faible, l'implementation est complexe, et HTTPS resout le meme problème de facon plus complète. Tu le trouveras encore dans certains protocoles SIP (telephonie VoIP) mais rarement sur le web.
401 vs 403 : la confusion permanente
Ces deux codes sont différents et cette différence compte.
401 Unauthorized : tu n'es pas authentifié. Le serveur ne sait pas qui tu es. Presente tes identifiants et reessaie. La réponse inclut un header WWW-Authenticate pour te dire comment t'authentifier.
403 Forbidden : tu es authentifié, mais tu n'as pas le droit. Le serveur sait qui tu es, mais cette ressource t'est interdite. Renvoyer des identifiants ne changera rien.
Un cas courant : un utilisateur standard qui tente d'acceder a /admin. Le serveur sait que c'est Jean, mais Jean n'est pas admin. C'est un 403, pas un 401.
Nuance supplementaire : certains serveurs renvoient un 404 au lieu d'un 403 pour ne pas reveler l'existence d'une ressource protégée. Si tu n'es pas admin, tu n'as meme pas besoin de savoir que /admin existe.
Proxy-Authorization
Quand un proxy intermediaire exige une authentification, il utilise un couple de headers parallèle :
# Le proxy demande
HTTP/1.1 407 Proxy Authentication Required
Proxy-Authenticate: Basic realm="proxy"
# Le client repond
Proxy-Authorization: Basic bmljb2xhczpwcm94eQ==
C'est le meme mecanisme que WWW-Authenticate / Authorization, mais entre le client et le proxy au lieu du client et le serveur. Le code de réponse est 407 au lieu de 401.
Tu rencontreras ca dans les réseaux d'entreprise avec des proxies HTTP qui filtrent le trafic. Le client s'authentifié auprès du proxy (407/Proxy-Authorization) puis auprès du serveur final (401/Authorization). Deux couches d'authentification independantes.
Quel mecanisme choisir ?
| Cas d'usage | Mecanisme |
|---|---|
| API publique avec quotas | Cle API dans un header |
| SPA avec sessions utilisateur | Bearer token (JWT) |
| Communication machine-a-machine | Bearer token ou mTLS |
| Outil interne rapide | Basic auth sur HTTPS |
| Proxy d'entreprise | Proxy-Authorization |
Le choix depend du contexte. Mais une regle ne change jamais : tous ces mecanismes necessitent HTTPS. Sans chiffrement, l'authentification est un theatre de sécurité.
Résumé
WWW-Authenticateannonce le schema,Authorizationenvoie les identifiants- Basic auth encode en Base64 sans chiffrer : HTTPS obligatoire
- Les tokens Bearer (JWT) permettent une authentification stateless
- Les clés API vont dans un header, jamais dans la query string
- 401 = pas authentifié, 403 = pas autorise, la distinction est fondamentale
- Digest auth est obsolète, HTTPS le remplace avantageusement
- Proxy-Authorization gere l'authentification auprès des proxies intermediaires
Article précédent : 11 - La negociation de contenu
Article suivant : 13 - CORS