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 URIs doivent ê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 grant est supprimé de la spécification
  • Les Bearer token ne 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 :

1
2
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="https://auth.example.com"

Ou avec un token expiré :

1
2
3
4
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="https://auth.example.com",
                  error="invalid_token",
                  error_description="The access token expired"

Dans le cas où le token est valide, mais ne dispose pas des scopes suffisants :

1
2
3
4
5
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"

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

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.

0%