Contactez-nous

Authentification via OAuth2 / OpenID Connect (connexion via Google, Facebook, etc.)

Facilitez l'authentification de vos utilisateurs Spring Boot en intégrant la connexion via des fournisseurs OAuth2/OIDC comme Google ou GitHub grâce à Spring Security.

Simplifier l'accès : pourquoi utiliser OAuth2/OIDC ?

Dans le paysage web actuel, les utilisateurs jonglent avec de nombreux comptes et mots de passe. Offrir une option de connexion via des fournisseurs d'identité établis et fiables comme Google, Facebook, GitHub, ou Okta (souvent appelée "connexion sociale") présente des avantages considérables. Cela élimine la nécessité pour l'utilisateur de créer et mémoriser un nouveau mot de passe spécifique à votre application, réduisant ainsi la friction à l'inscription et à la connexion.

Les protocoles OAuth2 (Open Authorization 2.0) et OpenID Connect (OIDC) sont les standards de l'industrie qui rendent cette intégration possible de manière sécurisée. OAuth2 est principalement un framework d'autorisation déléguée, permettant à une application d'obtenir un accès limité aux ressources d'un utilisateur sur un autre service, sans exposer les identifiants de l'utilisateur. OpenID Connect est une couche d'identité construite au-dessus d'OAuth2, spécifiquement conçue pour vérifier l'identité de l'utilisateur final et obtenir des informations de profil de base de manière interopérable.

En intégrant l'authentification OAuth2/OIDC, vous déléguez la complexité de la gestion des mots de passe et une partie du processus de vérification d'identité à des plateformes robustes, tout en offrant une expérience utilisateur fluide et familière. Spring Security, via son module `oauth2-client`, fournit un support exceptionnel pour intégrer ces flux dans votre application Spring Boot.

Distinction clé : OAuth2 (autorisation) vs OpenID Connect (authentification)

Il est important de comprendre la différence fondamentale entre OAuth2 et OIDC, bien que les termes soient souvent utilisés de manière interchangeable dans le contexte de la connexion sociale.

OAuth2 a été conçu à l'origine pour l'autorisation. Son objectif principal est de permettre à une application tierce (le "Client" - votre application) d'accéder à des ressources protégées hébergées sur un autre serveur (le "Resource Server" - par exemple, l'API Google Calendar) pour le compte du propriétaire de la ressource (l'"Utilisateur"), avec l'approbation de ce dernier via un "Authorization Server" (le serveur d'authentification de Google). Le résultat typique d'un flux OAuth2 est un `access_token`, qui représente cette autorisation limitée.

OpenID Connect (OIDC) est une surcouche d'OAuth2 qui ajoute la dimension d'authentification. Il utilise les flux OAuth2 mais introduit un élément supplémentaire : l'`id_token`. Cet `id_token` est un JSON Web Token (JWT) signé qui contient des informations vérifiées sur l'identité de l'utilisateur (comme son ID unique, son email, son nom, etc.). OIDC standardise la manière dont le Client peut demander et recevoir ces informations d'identité.

Pour la fonctionnalité "Se connecter avec X", c'est techniquement OIDC qui est utilisé la plupart du temps, car l'objectif est bien de vérifier l'identité de l'utilisateur et d'obtenir des informations le concernant pour établir une session dans votre application. Spring Security `oauth2-client` gère nativement les flux OIDC lorsque le fournisseur les supporte.

Intégration simplifiée avec `spring-boot-starter-oauth2-client`

Spring Boot simplifie radicalement l'intégration des flux OAuth2/OIDC grâce au starter `spring-boot-starter-oauth2-client`. Ajoutez simplement cette dépendance à votre projet Maven ou Gradle :

Maven (`pom.xml`):


    org.springframework.boot
    spring-boot-starter-oauth2-client

Gradle (`build.gradle`):

implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

Une fois cette dépendance présente, l'auto-configuration de Spring Boot active les fonctionnalités OAuth2 Client. Vous n'avez plus qu'à configurer les détails de vos fournisseurs d'identité (appelés "Clients" ou "Registrations" dans la terminologie Spring Security) via votre fichier `application.properties` ou `application.yml`.

Spring Security fournit même des configurations prédéfinies pour les fournisseurs les plus courants (Google, GitHub, Facebook, Okta) via l'énumération `CommonOAuth2Provider`, ce qui réduit encore la quantité de configuration nécessaire.

Configuration des fournisseurs dans `application.yml`

La configuration s'effectue sous la clé `spring.security.oauth2.client`. Vous devez d'abord enregistrer votre application auprès de chaque fournisseur d'identité que vous souhaitez supporter (par exemple, via Google Cloud Console pour Google, ou dans les Developer Settings pour GitHub). Ce processus vous fournira un `Client ID` et un `Client Secret` uniques pour votre application.

Voici des exemples de configuration pour Google et GitHub en YAML (`application.yml`) :

spring:
  security:
    oauth2:
      client:
        registration:
          # Configuration pour Google
          google:
            # Fourni par Google après enregistrement de l'application
            client-id: VOTRE_CLIENT_ID_GOOGLE 
            client-secret: VOTRE_CLIENT_SECRET_GOOGLE
            # Scopes demandés (openid, profile, email sont standards pour OIDC)
            scope:
              - openid
              - profile
              - email
            # Pas besoin de spécifier les endpoints (authorization-uri, token-uri, etc.)
            # car Google est un CommonOAuth2Provider connu de Spring Security.

          # Configuration pour GitHub
          github:
            # Fourni par GitHub après enregistrement de l'application
            client-id: VOTRE_CLIENT_ID_GITHUB
            client-secret: VOTRE_CLIENT_SECRET_GITHUB
            # Scopes pour GitHub (peuvent différer)
            scope:
              - read:user # Pour lire le profil utilisateur
              - user:email # Pour lire l'email (peut nécessiter une vérification)
            # GitHub n'est pas OIDC par défaut, mais Spring Security le gère bien.
            # Les endpoints sont aussi connus via CommonOAuth2Provider.

        # Configuration des fournisseurs (moins couramment nécessaire si CommonOAuth2Provider est utilisé)
        # provider:
        #   custom-provider:
        #     authorization-uri: ...
        #     token-uri: ...
        #     user-info-uri: ...
        #     user-name-attribute: ...

Points importants :

  • `client-id` / `client-secret`: Identifiants uniques de votre application auprès du fournisseur. Ne committez jamais les secrets dans votre code source ! Utilisez des variables d'environnement ou des systèmes de gestion de secrets.
  • `scope`: Définit les permissions que votre application demande à l'utilisateur (par exemple, accéder à l'email, au profil). `openid`, `profile`, `email` sont des scopes OIDC standards.
  • `redirect-uri`: L'URL vers laquelle le fournisseur redirigera l'utilisateur après l'authentification/autorisation. Par défaut, Spring Security configure automatiquement une URL au format `{baseUrl}/login/oauth2/code/{registrationId}` (par exemple, `/login/oauth2/code/google`). Vous devez enregistrer cette URL exacte auprès du fournisseur.

Le déroulement du flux d'authentification (Authorization Code Grant)

Lorsque vous activez l'authentification OAuth2 client (par exemple avec `http.oauth2Login(withDefaults());` dans votre configuration `SecurityFilterChain`), Spring Security met en place le flux "Authorization Code Grant", qui est le plus sécurisé et le plus courant pour les applications web :

  1. L'utilisateur clique sur un lien "Se connecter avec Google" (qui pointe vers `/oauth2/authorization/google` par défaut).
  2. Spring Security intercepte cette requête et redirige le navigateur de l'utilisateur vers l'URL d'autorisation de Google (`authorization-uri`), en incluant le `client-id`, les `scope` demandés et le `redirect-uri`.
  3. Google authentifie l'utilisateur (s'il n'est pas déjà connecté à Google) et lui présente un écran de consentement demandant l'autorisation pour les scopes requis par votre application.
  4. L'utilisateur donne son consentement.
  5. Google redirige le navigateur vers le `redirect-uri` de votre application, en ajoutant un `authorization_code` temporaire dans l'URL.
  6. Votre application Spring Boot reçoit cette redirection à l'URL `/login/oauth2/code/google`. Spring Security intercepte cet appel.
  7. En arrière-plan, Spring Security échange cet `authorization_code` (ainsi que le `client-id` et `client-secret`) contre un `access_token` (et un `id_token` si OIDC) en communiquant directement avec le `token-uri` de Google.
  8. Avec l'`access_token` ou l'`id_token`, Spring Security récupère les informations de l'utilisateur (depuis le `user-info-uri` de Google ou en décodant l'`id_token`).
  9. Spring Security crée un objet `OAuth2AuthenticationToken` représentant l'utilisateur authentifié (contenant ses détails et autorités) et le place dans le `SecurityContextHolder`. La session de l'utilisateur est établie dans votre application.
  10. L'utilisateur est redirigé vers la page qu'il visait initialement ou vers la page de succès par défaut.

Accéder aux informations de l'utilisateur authentifié

Une fois l'utilisateur authentifié via OAuth2/OIDC, vous pouvez accéder à ses informations dans vos contrôleurs ou services. L'objet `Principal` stocké dans le `SecurityContext` est généralement une instance de `org.springframework.security.oauth2.core.user.OAuth2User`.

Le moyen le plus simple d'y accéder dans un contrôleur est d'utiliser l'annotation `@AuthenticationPrincipal` :

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @GetMapping("/profil")
    public String userProfile(Model model, @AuthenticationPrincipal OAuth2User principal) {
        if (principal != null) {
            // Attributs standards et spécifiques au fournisseur
            String name = principal.getAttribute("name"); 
            String email = principal.getAttribute("email");
            String githubLogin = principal.getAttribute("login"); // Spécifique à GitHub
            String googleId = principal.getAttribute("sub"); // Standard OIDC (Subject)
            
            model.addAttribute("userName", name != null ? name : principal.getName());
            model.addAttribute("userEmail", email);
            model.addAttribute("attributes", principal.getAttributes()); // Tous les attributs
        } else {
            // Gérer le cas où l'utilisateur n'est pas authentifié
        }
        return "user-profile"; // Nom de la vue (template Thymeleaf, etc.)
    }
}

L'interface `OAuth2User` fournit la méthode `getAttributes()` qui retourne une `Map` contenant toutes les informations récupérées depuis le fournisseur (les noms des clés peuvent varier) et la méthode `getName()` qui retourne généralement l'identifiant unique de l'utilisateur chez le fournisseur (souvent le `sub` pour OIDC). Elle hérite aussi de `getAuthorities()` pour les rôles/permissions mappés.

Mapping des utilisateurs et enregistrement automatique

Un défi courant est de lier l'identité externe (par exemple, l'utilisateur Google) à un compte utilisateur interne dans votre propre base de données. Que faire la première fois qu'un utilisateur se connecte via Google ? Comment lui attribuer des rôles spécifiques à votre application ?

Spring Security vous permet de personnaliser ce processus en fournissant votre propre implémentation de l'interface `OAuth2UserService` (pour OAuth2) ou `OidcUserService` (pour OpenID Connect). Vous déclarez votre implémentation comme un `@Bean`.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.core.user.OAuth2User;

@Configuration
public class CustomOAuth2UserServiceConfig {

    // Exemple pour OIDC (Google, etc.)
    @Bean
    public OAuth2UserService oidcUserService(/* Injectez vos services/repositories ici */) {
        final OidcUserService delegate = new OidcUserService();

        return (userRequest) -> {
            // 1. Déléguer au service par défaut pour obtenir l'utilisateur OIDC standard
            OidcUser oidcUser = delegate.loadUser(userRequest);

            // 2. Extraire les informations nécessaires (email, nom, id fournisseur)
            String email = oidcUser.getEmail();
            String providerId = oidcUser.getSubject(); // ID unique chez le fournisseur
            String registrationId = userRequest.getClientRegistration().getRegistrationId(); // Ex: "google"

            // 3. Logique métier : chercher/créer l'utilisateur local
            // VotreUserRepository userRepository = ...;
            // UserEntity localUser = userRepository.findByProviderAndProviderId(registrationId, providerId)
            //     .orElseGet(() -> userRepository.save(createNewUser(oidcUser, registrationId)));

            // 4. Créer un nouvel objet UserDetails / OAuth2User / OidcUser 
            //    avec les autorités spécifiques à votre application.
            // Collection mappedAuthorities = mapAuthorities(localUser.getRoles());
            // oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
            
            // Retourner l'utilisateur (potentiellement enrichi/modifié)
            return oidcUser; 
        };
    }
    
    // Vous pourriez avoir un bean similaire pour OAuth2UserService
    // si vous supportez des fournisseurs non-OIDC comme GitHub.
}

Dans ce bean personnalisé, vous pouvez intercepter les informations de l'utilisateur fournies par l'IdP, interroger votre base de données, créer un nouvel utilisateur local si nécessaire (enregistrement automatique ou "just-in-time provisioning"), et mapper les rôles/autorités de votre application avant que l'objet `Authentication` final ne soit créé.