Maîtriser l'Authentification et l'Autorisation pour les Applications Web Modernes
Maîtriser l'Authentification et l'Autorisation pour les Applications Web Modernes

Comprendre OAuth 2.0 et ses Flux

Introduction : L'Autorisation Déléguée au Cœur des Applications Modernes

Dans l'écosystème du développement web moderne, la gestion de l'authentification (vérifier l'identité de l'utilisateur) et de l'autorisation (définir ce que l'utilisateur est autorisé à faire) est primordiale. Cependant, donner à une application tierce l'accès à nos données sans compromettre la sécurité est un défi. Imaginez que vous souhaitiez qu'une application de retouche photo accède à vos images stockées sur Google Photos, ou qu'une application de gestion de tâches puisse lire votre calendrier Google. Comment permettre cela sans donner votre mot de passe Google à chaque application ? C'est précisément le problème qu'OAuth 2.0 résout.

OAuth 2.0 est un protocole d'autorisation qui permet à une application (le "client") d'obtenir un accès limité aux ressources d'un utilisateur sur un autre service (le "serveur de ressources"), sans que l'utilisateur n'ait à partager ses identifiants. C'est une méthode de délégation sécurisée d'accès.

Ce que n'est PAS OAuth 2.0 :

  • Ce n'est PAS un protocole d'authentification. OAuth 2.0 ne vous dit pas qui est l'utilisateur, mais plutôt si l'utilisateur a autorisé une application à faire quelque chose en son nom. Pour l'authentification, on utilise souvent OpenID Connect, qui est une couche construite sur OAuth 2.0.
  • Ce n'est PAS un système de gestion d'utilisateurs. Il ne stocke pas de noms d'utilisateur ou de mots de passe.

Concepts Fondamentaux d'OAuth 2.0 : Les Acteurs Clés

Pour comprendre OAuth 2.0, il est essentiel de connaître les rôles et termes spécifiques :

  • Propriétaire des Ressources (Resource Owner) : C'est l'utilisateur final qui possède les données ou ressources protégées (ex: vos photos sur Google Photos, vos emails sur Gmail). C'est lui qui donne son consentement pour l'accès.

  • Client (Client) : L'application tierce qui souhaite accéder aux ressources du propriétaire des ressources (ex: l'application de retouche photo, l'application de gestion de tâches). Le client peut être une application web, mobile, desktop, etc.

    • Client Confidentiel : Une application capable de garder un secret (ex: une application web côté serveur). Elle peut stocker un client_secret en toute sécurité.
    • Client Public : Une application incapable de garder un secret (ex: une application SPA JavaScript exécutée dans un navigateur, une application mobile).
  • Serveur d'Autorisation (Authorization Server) : Le serveur qui interagit avec le propriétaire des ressources pour obtenir son autorisation et délivre les jetons d'accès au client. Il gère le processus d'autorisation.

  • Serveur de Ressources (Resource Server) : Le serveur qui héberge les ressources protégées de l'utilisateur (ex: l'API Google Photos, l'API Gmail). Il accepte les jetons d'accès et sert les ressources demandées.

  • Portées (Scopes) : Des chaînes de caractères qui définissent les permissions spécifiques que le client demande (ex: read_photos, write_calendar). L'utilisateur voit ces scopes et les approuve ou les rejette.

  • URI de Redirection (Redirect URI / Callback URL) : L'URL à laquelle le serveur d'autorisation renvoie le propriétaire des ressources (avec un code d'autorisation ou un jeton d'accès) après qu'il a donné son consentement. Cette URL doit être pré-enregistrée auprès du serveur d'autorisation.

  • Code d'Autorisation (Authorization Code) : Un code temporaire et à usage unique que le serveur d'autorisation fournit au client. Ce code est ensuite échangé contre un jeton d'accès.

  • Jeton d'Accès (Access Token) : La "clé" que le client utilise pour accéder aux ressources protégées du serveur de ressources. Il est généralement de courte durée et doit être inclus dans l'en-tête Authorization des requêtes HTTP.

  • Jeton de Rafraîchissement (Refresh Token) : Un jeton de longue durée qui peut être utilisé par le client (généralement confidentiel) pour obtenir un nouveau jeton d'accès lorsque l'ancien expire, sans avoir à redemander l'autorisation à l'utilisateur.

Le Fonctionnement Général d'OAuth 2.0 (Vue d'Ensemble)

Le flux OAuth 2.0 suit généralement ces étapes :

  1. Le client demande l'autorisation : L'utilisateur clique sur "Se connecter avec Google" ou "Accorder l'accès" dans l'application cliente.
  2. Redirection vers le Serveur d'Autorisation : Le client redirige le navigateur de l'utilisateur vers le serveur d'autorisation, en incluant des paramètres comme l'ID du client, les scopes demandés et l'URI de redirection.
  3. Consentement de l'Utilisateur : Le serveur d'autorisation authentifie l'utilisateur (s'il ne l'est pas déjà) et lui demande de donner ou de refuser son consentement pour que le client accède aux ressources demandées (en fonction des scopes).
  4. Réponse du Serveur d'Autorisation : Si l'utilisateur donne son consentement, le serveur d'autorisation redirige le navigateur de l'utilisateur vers l'URI de redirection du client, en y joignant un code d'autorisation (ou, dans certains flux, directement un jeton d'accès).
  5. Échange du Code contre un Jeton d'Accès (pour certains flux) : Le client (côté serveur) reçoit le code d'autorisation et l'échange directement avec le serveur d'autorisation (via une requête sécurisée de serveur à serveur) contre un jeton d'accès (et potentiellement un jeton de rafraîchissement).
  6. Accès aux Ressources : Le client utilise le jeton d'accès pour faire des requêtes aux API du serveur de ressources, en incluant le jeton dans l'en-tête Authorization (généralement sous la forme Bearer <access_token>).

Les Flux OAuth 2.0 (Grant Types)

OAuth 2.0 définit plusieurs "types d'octroi" (Grant Types), chacun adapté à des scénarios d'utilisation différents en fonction du type de client et des exigences de sécurité.

1. Flux de Code d'Autorisation (Authorization Code Flow)

C'est le flux le plus recommandé et le plus sécurisé pour les applications web côté serveur (confidential clients). Il est également utilisé pour les applications mobiles et SPAs avec l'extension PKCE.

Fonctionnement :

  1. Le client redirige le navigateur de l'utilisateur vers le serveur d'autorisation.
  2. L'utilisateur s'authentifie et donne son consentement.
  3. Le serveur d'autorisation redirige l'utilisateur vers le redirect_uri du client avec un authorization_code.
  4. Le client (côté serveur) reçoit ce authorization_code.
  5. Le client effectue une requête directement au serveur d'autorisation (server-to-server) pour échanger le authorization_code contre un access_token (et un refresh_token), en incluant également son client_id et client_secret.
  6. Le serveur d'autorisation valide le authorization_code et le client_secret et renvoie les jetons.
  7. Le client utilise l'access_token pour faire des requêtes au serveur de ressources.

Avantages :

  • Sécurité maximale : Le jeton d'accès n'est jamais exposé dans le navigateur de l'utilisateur. L'échange authorization_code contre access_token se fait via une connexion directe et sécurisée de serveur à serveur, protégeant ainsi le client_secret.
  • Supporte les refresh_token pour un accès continu sans ré-authentification de l'utilisateur.

Quand l'utiliser : Applications web traditionnelles (avec backend), applications mobiles et Single Page Applications (SPAs) en combinaison avec PKCE.

Exemple de Requêtes (Conceptualisation des étapes) :

  1. Requête d'autorisation initiale (via le navigateur de l'utilisateur) : Le client construit une URL et y redirige l'utilisateur.

    <!-- Côté client (HTML ou JavaScript) -->
    <a href="https://auth.example.com/oauth/authorize?
        response_type=code&
        client_id=YOUR_CLIENT_ID&
        redirect_uri=https://your-app.com/callback&
        scope=read_profile%20read_photos&
        state=RANDOM_STATE_STRING"
    >
        Se connecter avec Mon Service
    </a>
    
    • response_type=code : Indique que l'on attend un code d'autorisation.
    • client_id : L'identifiant de votre application.
    • redirect_uri : L'URL où le serveur d'autorisation renverra l'utilisateur.
    • scope : Les permissions demandées.
    • state : Une chaîne aléatoire pour prévenir les attaques CSRF.
  2. Échange du code contre les jetons (requête server-to-server) : Après que l'utilisateur a donné son consentement, le serveur d'autorisation redirige vers https://your-app.com/callback?code=YOUR_AUTH_CODE&state=RANDOM_STATE_STRING. Votre serveur backend intercepte cette requête et fait une nouvelle requête au serveur d'autorisation.

    # Requête cURL depuis votre serveur backend
    curl -X POST https://auth.example.com/oauth/token \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -d "grant_type=authorization_code&" \
      -d "code=YOUR_AUTH_CODE&" \
      -d "redirect_uri=https://your-app.com/callback&" \
      -d "client_id=YOUR_CLIENT_ID&" \
      -d "client_secret=YOUR_CLIENT_SECRET"
    
    • grant_type=authorization_code : Spécifie le type d'octroi.
    • code : Le code d'autorisation reçu.
    • redirect_uri : Doit correspondre à celle de la première étape.
    • client_id et client_secret : Utilisés pour authentifier votre application.

    La réponse du serveur d'autorisation ressemblera à :

    {
      "access_token": "YOUR_ACCESS_TOKEN",
      "token_type": "Bearer",
      "expires_in": 3600,
      "refresh_token": "YOUR_REFRESH_TOKEN",
      "scope": "read_profile read_photos"
    }
    

2. Flux Implicite (Implicit Flow)

Ce flux était précédemment utilisé pour les applications web côté client (SPAs) et les applications mobiles (public clients), mais il est désormais considéré comme moins sécurisé et déprécié au profit du flux de code d'autorisation avec PKCE.

Fonctionnement :

  1. Le client redirige le navigateur de l'utilisateur vers le serveur d'autorisation.
  2. L'utilisateur s'authentifie et donne son consentement.
  3. Le serveur d'autorisation redirige l'utilisateur vers le redirect_uri du client avec l'access_token directement dans le fragment de l'URL (#access_token=...).
  4. Le JavaScript côté client extrait l'access_token du fragment de l'URL.

Inconvénients (pourquoi déprécié) :

  • L'access_token est exposé dans l'URL du navigateur, ce qui le rend vulnérable aux fuites via les logs du navigateur, les historiques ou les serveurs intermédiaires.
  • Ne prend pas en charge les refresh_token, obligeant l'utilisateur à se ré-authentifier une fois l'accès expiré.
  • Aucune authentification du client (client_secret n'est pas utilisé), ce qui rend le client moins "sûr".

Quand l'utiliser : À éviter. Toujours préférer le flux de code d'autorisation avec PKCE pour les clients publics.

3. Flux d'Identifiants du Client (Client Credentials Flow)

Ce flux est conçu pour les interactions de machine à machine, où le client est lui-même le propriétaire des ressources ou agit en son propre nom (par exemple, un service backend appelant une API externe). Il n'y a pas d'utilisateur final impliqué.

Fonctionnement :

  1. Le client envoie directement son client_id et son client_secret au serveur d'autorisation (endpoint de jeton).
  2. Le serveur d'autorisation valide les informations d'identification du client.
  3. Le serveur d'autorisation renvoie un access_token au client.
  4. Le client utilise cet access_token pour accéder aux ressources protégées du serveur de ressources.

Avantages :

  • Simple et direct pour les communications de service à service.
  • Pas d'interaction utilisateur requise.

Quand l'utiliser : Lorsque votre application (un service backend, un script, un microservice) a besoin d'accéder à une API en son propre nom, sans qu'un utilisateur final ne soit impliqué (par exemple, un service de traitement de données qui interroge une API externe).

Exemple de Requête :

# Requête cURL depuis votre service backend
curl -X POST https://auth.example.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&" \
  -d "client_id=YOUR_CLIENT_ID&" \
  -d "client_secret=YOUR_CLIENT_SECRET&" \
  -d "scope=read_analytics" # Scopes spécifiques aux permissions du client

La réponse du serveur d'autorisation est similaire à celle du flux de code d'autorisation, mais sans refresh_token (car il n'y a pas d'utilisateur à "rafraîchir").

4. Flux des Informations d'Identifiant du Propriétaire des Ressources (Resource Owner Password Credentials Flow)

Ce flux permet au client de demander directement les identifiants de l'utilisateur (nom d'utilisateur et mot de passe) et de les envoyer au serveur d'autorisation pour obtenir un jeton d'accès.

Fonctionnement :

  1. L'utilisateur entre son nom d'utilisateur et son mot de passe dans l'interface du client.
  2. Le client envoie ces identifiants (avec son client_id et client_secret) au serveur d'autorisation.
  3. Le serveur d'autorisation authentifie l'utilisateur et renvoie un access_token (et potentiellement un refresh_token) au client.

Inconvénients (fortement déconseillé) :

  • Risque de sécurité majeur : Le client doit gérer et transmettre les identifiants de l'utilisateur, ce qui est une violation directe du principe de "ne jamais demander le mot de passe de l'utilisateur à une application tierce". Si le client est compromis, les identifiants de l'utilisateur le sont aussi.
  • Va à l'encontre de la philosophie d'OAuth de ne pas partager les mots de passe.
  • Ne permet pas au serveur d'autorisation d'afficher des pages de consentement ou de gérer des politiques de sécurité avancées (MFA, CAPTCHA, etc.).

Quand l'utiliser : Rarement, et seulement dans des cas très spécifiques et contrôlés. Typiquement, pour les applications de première partie hautement fiables (ex: une application mobile native développée par le même fournisseur de service que l'API). Même dans ces cas, le flux de code d'autorisation avec PKCE est souvent préférable.

Sécurité Avancée : PKCE (Proof Key for Code Exchange)

Le "Proof Key for Code Exchange" (PKCE, prononcé "pixie") est une extension du flux de code d'autorisation, conçue pour sécuriser les clients publics (applications mobiles et SPAs) qui ne peuvent pas stocker de client_secret en toute sécurité.

Le problème que PKCE résout : Sans PKCE, un attaquant pourrait intercepter le authorization_code redirigé vers l'application publique et l'échanger lui-même contre un jeton d'accès.

Fonctionnement de PKCE :

  1. Le client génère une chaîne aléatoire unique appelée code_verifier.
  2. Il génère un code_challenge à partir du code_verifier (généralement via hachage SHA256 et encodage Base64Url).
  3. Étape 1 (Requête d'autorisation) : Le client redirige l'utilisateur vers le serveur d'autorisation, en incluant le code_challenge et la méthode de hachage (code_challenge_method).
  4. Étape 2 (Consentement) : L'utilisateur donne son consentement, et le serveur d'autorisation redirige l'utilisateur vers le redirect_uri avec le authorization_code.
  5. Étape 3 (Échange de jetons) : Le client envoie le authorization_code et le code_verifier (non haché) au serveur d'autorisation pour l'échange de jetons.
  6. Étape 4 (Validation) : Le serveur d'autorisation recalcule le code_challenge à partir du code_verifier reçu et vérifie qu'il correspond au code_challenge original reçu lors de l'étape 1. S'ils correspondent, il délivre les jetons.

Si un attaquant intercepte le authorization_code, il ne pourra pas l'échanger sans le code_verifier original, que seul le client légitime connaît.

Quand l'utiliser : Toujours pour les clients publics (SPAs, applications mobiles, applications desktop natives) qui utilisent le flux de code d'autorisation. C'est la norme de sécurité actuelle pour ces types d'applications.

Conclusion : Maîtriser l'Autorisation Déléguée

OAuth 2.0 est un standard puissant et flexible pour l'autorisation déléguée, essentiel dans le développement d'applications web modernes. Comprendre ses concepts fondamentaux et savoir quel flux utiliser pour quel scénario est crucial pour bâtir des applications sécurisées et interopérables.

  • Leçon clé : OAuth 2.0 concerne l'autorisation, pas l'authentification. Il permet à une application d'agir au nom d'un utilisateur sans connaître ses identifiants.
  • Choisissez le bon flux :
    • Authorization Code Flow (avec ou sans PKCE) : Le choix par défaut et le plus sécurisé pour la plupart des applications (web, mobile, SPA). PKCE est obligatoire pour les clients publics.
    • Client Credentials Flow : Idéal pour les communications de machine à machine (service à service).
    • Implicit Flow et Resource Owner Password Credentials Flow : Généralement à éviter en raison de leurs failles de sécurité inhérentes ou de leurs risques élevés.

En suivant ces principes et en implémentant scrupuleusement les meilleures pratiques de sécurité (HTTPS, validation des URI de redirection, utilisation de state et PKCE), vous pouvez intégrer des services tiers et protéger les données de vos utilisateurs de manière robuste et fiable. OAuth 2.0 est la pierre angulaire de l'interconnexion sécurisée dans le monde numérique d'aujourd'hui.