OAuth 2.1 - Une Évolution Pas Si Anodine
Oauth 2.1 est encore en draft mais l’on peut déjà voir les évolutions qui arriveront par rapport à OAuth 2.0. OAuth 2.1 est décrit comme une consolidation des bonnes pratiques et des extensions ajoutées à OAuth 2.0. Nous allons parler d’une fonctionnalité en particulier qui à mon sens est un gros plus, mais n’est, pourtant pas du tout mis en avant.
Les nouveautés de OAuth 2.1
Sur le site de la spécification les principaux changements mis en avant sont les suivants :
- PKCE est maintenant requis pour tous les clients OAuth utilisant le flow
Authorization Code - Les
Redirect URIsdoivent être comparées avec une égalité parfaite. Plus de wildcard (*) - L’
Implicit grant(response_type=token) est supprimé de la spécification - Le
Resource Owner Password Credentials grantest supprimé de la spécification - Les
Bearer tokenne sont plus utilisables dans les paramètres des URIs. - Les Refresh tokens pour les clients publics doivent être soit must contraint par l’expéditeur soit utilisable une unique fois.
- Les définitions de clients publics et confidentiels ont été simplifiés et ne font plus référence qu’à la possession ou non d’une accréditation par le client.
Comme je le disais en intro, cela ne fait que pérenniser des bonnes pratiques déjà employées avec OAuth2.
Header WWW-Authenticate, le header qui change tout.
Une nouveauté qui pourrait presque passer inaperçu mais qui change pour moi beaucoup de chose est la section 5.3.1. The WWW-Authenticate Response Header Field.
Le concept est qu’en cas d’échec lors de l’appel d’un endpoint, une réponse avec un code 401/403 est renvoyé et un header WWW-Authenticate doit ajouté à la réponse. Ce Header peut avoir les attributs suivants :
- realm: Le royaume gérant les authorizations pour le serveur de ressource
- scope: La liste des scopes requis pour accéder au endpoint demandé
- error: Un code d’erreur. Les valeurs possibles sont
invalid_request,invalid_token,insufficient_scope - error_description: Une description de l’erreur
- error_uri: Un lien permettant d’avoir de plus amples information sur l’erreur
Par exemple en cas de code 401 pour une requète sans token :
Ou avec un token expiré :
Dans le cas où le token est valide, mais ne dispose pas des scopes suffisants :
Ces apports à priori anodins permettent de découpler complétement un client des serveurs de ressource d’un point de vue autorisation d’accès. Le serveur de ressource est maintenant capable d’indiquer auprès de quel royaume demander un token et quels scopes celui-ci doit contenir pour être valide.
Cela permet de rendre complétement dynamique la gestion des droits sans avoir à redéployer une mise à jour des clients. Ceux-ci iront automatiquement chercher les nouveaux scopes nécessaire.
La spécification ne précise pas comment le serveur de ressource récupère la liste des scopes à renseigner dans le token. Le plus simple est de passer par un système de convention. Ainsi le endpoint POST /users aura besoin du scope user-add. une autre solution est d’avoir un endpoint exposé par le serveur d’autorisation que le serveur de ressource pourrait interroger pour connaitre la liste des scopes nécessaire pour un endpoint.
Dans le deuxième cas, un manque de standardisation entre les serveurs d’autorisation se fera rapidement ressentir et on se tournera volontiers vers une extension OAuth, appelée UMA 2, répondant justement à ces problématiques et proposant le même mécanisme de header WWW-Authenticate.
---
config:
noteAlign: left
---
sequenceDiagram
autonumber
participant Client
participant ResourceServer
participant AuthorizationServer
Client->>ResourceServer: Initial request without token or with missing scope
alt Requesting scope to AS
ResourceServer->>AuthorizationServer: Ask for required scopes
AuthorizationServer->>ResourceServer: Send Required scopes
else Handling required scope locally
ResourceServer->>ResourceServer: compute scopes via convention or configuration
end
ResourceServer->>Client: 403 - WWW-Autenticate header (realm + scope + error)
Note left of ResourceServer: HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer realm="https://auth.example.com",
error="insufficient_scope",
error_description="Bearer token is missing required scopes"
scope="openid user-list user-add"
Client->>AuthorizationServer: Ask for a token with required scope
AuthorizationServer->>Client: Check Rights and send token with requested scopes
Client->>ResourceServer: Send request with token with needed scopes
ResourceServer->>Client: Send requested data
---
config:
noteAlign: left
---
sequenceDiagram
autonumber
participant Client
participant ResourceServer
participant AuthorizationServer
Client->>ResourceServer: Initial request without token or with missing scope
alt Requesting scope to AS
ResourceServer->>AuthorizationServer: Ask for required scopes
AuthorizationServer->>ResourceServer: Send Required scopes
else Handling required scope locally
ResourceServer->>ResourceServer: compute scopes via convention or configuration
end
ResourceServer->>Client: 403 - WWW-Autenticate header (realm + scope + error)
Note left of ResourceServer: HTTP/1.1 403 Forbidden WWW-Authenticate: Bearer realm="https://auth.example.com",
error="insufficient_scope",
error_description="Bearer token is missing required scopes"
scope="openid user-list user-add" Client->>AuthorizationServer: Ask for a token with required scope AuthorizationServer->>Client: Check Rights and send token with requested scopes Client->>ResourceServer: Send request with token with needed scopes ResourceServer->>Client: Send requested data
Conclusion
OAuth 2.1 est une évolution attendue de longue date et tirant profit des bonnes pratiques et l’expérience d’OAuth2. L’apport du header WWW-Autenticate de manière standard dans la spécification permet d’envisager une réduction de la maintenance des applications grâce à une prise en compte dynamique des changements d’autorisations des serveurs de ressources.