Aller au contenu principal
Retour aux tutos
GratuitIntermédiaireCybersécurité

Ajouter le SSO Google et Microsoft à une application — Guide OIDC complet

Guide complet et vendor-neutre pour ajouter 'Se connecter avec Google' et 'Se connecter avec Microsoft' à votre application. OpenID Connect (OIDC), flux Authorization Code + PKCE, configuration Google Cloud et Entra ID, validation d'ID token, checklist de mise en production, exemples Node.js et Python.

26 juin 202645 min

Vous saurez faire

  • Comprendre la mécanique OIDC sans réinventer la cryptographie
  • Configurer un client OAuth Google + une App Registration Microsoft Entra correctement
  • Implémenter le flux Authorization Code + PKCE avec une bibliothèque certifiée
  • Valider l'ID token côté serveur (signature, iss, aud, exp, nonce)
  • Éviter les 6 pièges qui transforment un SSO en faille de sécurité

Pré-requis

  • Application web ou mobile dont vous contrôlez le back-end (ou un broker d'identité)
  • Notions de HTTPS, JSON Web Tokens (JWT), variables d'environnement
  • Accès admin à Google Cloud Console et/ou Microsoft Entra admin center
Sommaire18

1. Objectif & périmètre

Permettre à un utilisateur de se connecter à votre application avec son compte Google (Gmail / Google Workspace) ou Microsoft (compte professionnel/scolaire Entra ID, ou compte personnel), sans créer de nouveau mot de passe — c'est le SSO (Single Sign-On).

Le standard à utiliser est OpenID Connect (OIDC), une couche d'authentification posée au-dessus d'OAuth 2.0 (qui gère l'autorisation). Google et Microsoft sont tous deux des fournisseurs OIDC conformes : la même mécanique s'applique aux deux, seuls les paramètres de configuration changent.

Principe directeur

Ne réécrivez jamais la cryptographie ni la validation de jetons vous-même. Utilisez une bibliothèque OIDC certifiée (openid-client, Authlib, Microsoft.Identity.Web, Spring Security…) ou un broker d'identité (Keycloak, Auth0/Okta, Microsoft Entra External ID). Ce guide vous donne le vocabulaire et les bonnes configurations — la bibliothèque fait le reste.

2. Vocabulaire indispensable

TermeSignification
IdP (Identity Provider)Le fournisseur d'identité : Google, Microsoft Entra ID.
RP / ClientVotre application (Relying Party), qui « fait confiance » à l'IdP.
ID tokenUn JWT signé qui prouve qui est l'utilisateur (authentification). Pièce maîtresse du SSO.
Access tokenJeton d'autorisation pour appeler une API. Ne sert pas à authentifier.
Refresh tokenJeton permettant d'obtenir de nouveaux tokens sans réauthentification.
ScopesPérimètre demandé. Pour le SSO : openid email profile.
ClaimsInfos sur l'utilisateur dans l'ID token (sub, email, name, email_verified…).
redirect_uriURL de votre app où l'IdP renvoie l'utilisateur. Pré-enregistrée à l'identique.
stateValeur aléatoire anti-CSRF, vérifiée au retour.
nonceValeur aléatoire anti-rejeu, liée à l'ID token.
PKCEProtection du code d'autorisation (RFC 7636). Obligatoire pour clients publics, recommandée pour tous.
Discovery documentURL standard /.well-known/openid-configuration listant endpoints et clés de l'IdP.
JWKSLe jeu de clés publiques de l'IdP servant à vérifier la signature des jetons.

3. Choisir son approche

3.1 Type d'application (détermine la sécurité)

Client confidentiel (web back-end)

Le back-end garde un secret. Utilise un client_secret (ou un certificat). Échange le code côté serveur. Cas le plus fréquent.

Client public (SPA / mobile / desktop)

Pas de secret (il serait exposé). PKCE est obligatoire. La bibliothèque OIDC le gère pour vous.

3.2 Intégration directe ou broker ?

Bibliothèque OIDC par fournisseur

Recommandé pour démarrer simple. Google et Microsoft intégrés comme deux fournisseurs OIDC derrière une couche commune dans votre app.

Broker d'identité (Keycloak, Auth0, Entra External ID…)

Un seul point d'intégration. Le broker prend en charge Google, Microsoft, SAML, MFA, sessions. Indispensable dès que vous avez plusieurs IdP, plusieurs apps, ou des besoins entreprise (MFA, provisioning SCIM, audit).

Quel que soit le choix, traitez Google et Microsoft de façon homogène : deux boutons « Se connecter avec… » qui déclenchent le même flux OIDC avec des paramètres différents.

4. Le flux recommandé : Authorization Code + PKCE (+ OIDC)

C'est le flux standard et sûr pour le SSO web. Six temps :

1

Clic utilisateur

L'utilisateur clique « Se connecter avec Google » ou « avec Microsoft ».

2

Redirection vers l'IdP

Votre app génère state, nonce et un couple PKCE (code_verifier secret + code_challenge), puis redirige le navigateur vers l'endpoint d'autorisation de l'IdP.

3

Authentification chez l'IdP

L'utilisateur s'authentifie chez l'IdP et consent aux scopes demandés.

4

Retour avec un code

L'IdP renvoie le navigateur vers votre redirect_uri avec un code d'autorisation à usage unique + le state.

5

Échange du code

Votre back-end vérifie le state, puis échange le code contre des jetons à l'endpoint de token (en envoyant le code_verifier, et le secret si client confidentiel).

6

Validation + session

Votre app valide l'ID token, extrait l'identité, crée/relie le compte local, ouvre une session applicative.

Exemple d'URL d'autorisation (paramètres clés, communs aux deux IdP) :

Texte
GET https://<endpoint_authorize_de_l_IdP>
  ?client_id=VOTRE_CLIENT_ID
  &response_type=code
  &redirect_uri=https://votre-app.example.com/auth/callback
  &scope=openid email profile
  &state=ALEA_ANTI_CSRF
  &nonce=ALEA_ANTI_REJEU
  &code_challenge=BASE64URL_SHA256_DU_VERIFIER
  &code_challenge_method=S256

5. Mise en place côté Google

  1. Aller dans Google Cloud Console → créer/sélectionner un projet.
  2. APIs & Services → OAuth consent screen : configurer l'écran de consentement (interne si Workspace, ou externe), nom, e-mail de support, domaines autorisés.
  3. APIs & Services → Credentials → Create credentials → OAuth client ID : type Application Web.
  4. Renseigner les Authorized redirect URIs (ex. https://votre-app.example.com/auth/callback) — exactes, en HTTPS.
  5. Récupérer le Client ID et le Client secret.
Texte
Discovery : https://accounts.google.com/.well-known/openid-configuration
Authorize : https://accounts.google.com/o/oauth2/v2/auth
Token     : https://oauth2.googleapis.com/token
JWKS      : https://www.googleapis.com/oauth2/v3/certs
UserInfo  : https://openidconnect.googleapis.com/v1/userinfo
Issuer    : https://accounts.google.com

Scopes SSO : openid email profile. Claims utiles : sub (identifiant stable), email, email_verified, name, picture, hd (domaine Workspace).

6. Mise en place côté Microsoft (Entra ID)

  1. Aller dans le Microsoft Entra admin centerApp registrationsNew registration.
  2. Supported account types : choisir selon le besoin — Single tenant (uniquement votre organisation), Multitenant (toutes les organisations Microsoft), Multitenant + comptes personnels (+ comptes Microsoft grand public). Ce choix détermine la valeur {tenant} des endpoints.
  3. Authentication → Redirect URIs : ajouter votre URI (plateforme Web), en HTTPS, à l'identique.
  4. Certificates & secrets : créer un client secret (copier la Value, pas le Secret ID ; définir une expiration et prévoir la rotation). Préférer un certificat au secret si possible.
  5. Récupérer l'Application (client) ID depuis la page Overview.
Texte
Discovery : https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration
Authorize : https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
Token     : https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
JWKS      : https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys
UserInfo  : https://graph.microsoft.com/oidc/userinfo

{tenant} = common (tous) / organizations (pro/scolaire) / consumers (perso) / ID de tenant précis. Scopes SSO : openid email profile. Claims utiles : sub, oid (utilisateur stable dans le tenant), tid (tenant), email / preferred_username.

⚠️ Piège multi-tenant Microsoft

L'issuer contient un identifiant de tenant variable. Si vous ne validez pas explicitement les tid / iss autorisés, n'importe quel tenant Microsoft pourra se connecter à votre app — il suffit qu'un attaquant crée un tenant Entra gratuit. Toujours maintenir une allowlist explicite des tid autorisés côté serveur.

7. Côté application : les étapes d'implémentation

1

Initier

Générer state, nonce, PKCE ; stocker temporairement (cookie signé / serveur) ; rediriger vers l'endpoint d'autorisation.

2

Callback

Vérifier que le state reçu correspond ; échanger le code contre les jetons à l'endpoint de token (avec code_verifier, et le secret si confidentiel).

3

Valider l'ID token

Côté serveur, impérativement : signature via le JWKS, iss attendu, aud = votre client_id, exp / iat valides (tolérance d'horloge ~ quelques minutes), nonce = celui envoyé.

4

Identité & compte

Lire les claims, relier au compte local par e-mail vérifié (email_verified = true) ou par sub / oid ; créer le compte au besoin ; ouvrir la session applicative.

5

Déconnexion

Invalider la session locale ; optionnellement déclencher la déconnexion côté IdP via l'end_session_endpoint.

8. Sécurité — points non négociables

Tout est de votre responsabilité, pas de celle du fournisseur

La sécurité d'une intégration SSO se joue entièrement côté votre application. L'IdP fait son travail si le vôtre est correct.

  • HTTPS partout. Aucune exception, y compris en pré-prod.
  • redirect_uri exacte et pré-enregistrée : pas de wildcard, attention à la casse et au slash final (correspondance stricte).
  • state (anti-CSRF) + nonce (anti-rejeu) systématiques, et PKCE même pour les clients confidentiels.
  • Validation de l'ID token côté serveur (signature, iss, aud, exp, nonce) — ne jamais faire confiance à un jeton non vérifié.
  • Secrets côté serveur uniquement : jamais dans un SPA, une app mobile ou un dépôt Git. Coffre, rotation, expiration. Côté Microsoft, préférer un certificat au secret.
  • Sessions/jetons : cookies HttpOnly + Secure + SameSite, pas dans localStorage. Sessions courtes, rotation des refresh tokens.
  • Liaison de comptes par e-mail vérifié uniquement (email_verified). Sinon, risque d'usurpation de compte.
  • Multi-tenant Microsoft : valider tid / iss autorisés.
  • Minimiser les scopes (openid email profile suffit ; ne demandez des scopes API qu'en cas de besoin réel).
  • JWKS : mise en cache + gestion de la rotation des clés de l'IdP.
  • Journalisation des connexions/échecs, anti-bruteforce, et révocation des accès à la sortie d'un collaborateur.

9. Les 6 pièges les plus fréquents

1 — Authentifier avec l'access token

L'access token est un jeton d'autorisation, pas d'authentification. L'ID token est l'unique source de vérité pour le SSO.

2 — redirect_uri non exacte

Slash, casse, http/https : la correspondance est stricte. Une virgule de plus → erreur de redirection.

3 — Pas de validation de tenant

En multi-tenant Microsoft, sans allowlist tid / iss, n'importe quel tenant Microsoft se connecte à votre app.

4 — Secret exposé dans un client public

Un secret dans un SPA, une app mobile ou un dépôt Git, c'est un secret public. Utilisez PKCE sans secret.

5 — Liaison sur e-mail non vérifié

Sans email_verified = true, n'importe qui peut créer un compte au nom d'un autre chez un IdP permissif et prendre le contrôle.

6 — Secret Microsoft expiré

Faute de rotation planifiée, l'expiration arrive en pleine prod. Plusieurs secrets actifs en parallèle = bascule sans coupure.

10. Bibliothèques recommandées (selon la stack)

StackBibliothèque
Node.jsopenid-client (certifiée OIDC), ou Passport avec stratégies Google/Microsoft
.NET / ASP.NET CoreMicrosoft.Identity.Web, middleware OpenIdConnect
Java / SpringSpring Security — OAuth2 Client
PythonAuthlib (ou python-social-auth)
PHPleague/oauth2-client + providers Google/Microsoft
Brokers / passerellesKeycloak, Authelia (open source) ; Auth0/Okta, Microsoft Entra External ID (managés)

11. Checklist de mise en production

Avant le go-live

Cochez toutes les cases. Tester avec un compte « cobaye » sur chaque branche de la matrice (nouveau / existant / refus consentement / token expiré / e-mail non vérifié / mauvais tenant).

  • Clients OAuth créés côté Google et Microsoft, redirect_uri de prod enregistrées (HTTPS, exactes)
  • Secrets en coffre, rotation planifiée, échéances suivies (Microsoft)
  • PKCE + state + nonce activés
  • Validation complète de l'ID token (signature/JWKS, iss, aud, exp, nonce)
  • Tenant Microsoft validé (si multi-tenant) ; e-mail vérifié exigé pour la liaison de comptes
  • Sessions en cookies HttpOnly / Secure / SameSite, durées courtes, déconnexion fonctionnelle
  • Scopes minimaux ; journalisation et procédure de révocation en place
  • Tests : nouveau compte, compte existant, refus de consentement, jeton expiré, e-mail non vérifié, mauvais tenant

12. Exemples de code commentés

Lecture des exemples

L'essentiel (PKCE, state, nonce, validation de l'ID token) est délégué à une bibliothèque certifiée. Le même code sert pour Google et Microsoft — seuls l'issuer et les identifiants changent. Adaptez selon la version de la bibliothèque.

12.1 Node.js — Express + openid-client

JavaScript
// SSO OIDC avec Google et Microsoft — Node.js (Express + openid-client v5)
// npm i express express-session openid-client
import express from 'express';
import session from 'express-session';
import { Issuer, generators } from 'openid-client';

const app = express();
app.use(session({
  secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false,
  cookie: { httpOnly: true, secure: true, sameSite: 'lax' }, // cookie de session sécurisé
}));

const REDIRECT = 'https://votre-app.example.com/auth/callback';

// 1) Découverte automatique des endpoints + création du client
async function makeClient(issuerUrl, clientId, clientSecret, redirectUri) {
  const issuer = await Issuer.discover(issuerUrl);
  return new issuer.Client({
    client_id: clientId,
    client_secret: clientSecret, // côté serveur UNIQUEMENT (client confidentiel)
    redirect_uris: [redirectUri],
    response_types: ['code'],
  });
}

const clients = {};
(async () => {
  // Google
  clients.google = await makeClient('https://accounts.google.com',
    process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, REDIRECT + '/google');
  // Microsoft (tenant = ID de tenant, 'organizations' ou 'common')
  clients.microsoft = await makeClient('https://login.microsoftonline.com/<tenant>/v2.0',
    process.env.MS_CLIENT_ID, process.env.MS_CLIENT_SECRET, REDIRECT + '/microsoft');
})();

// 2) Démarrage du login : PKCE + state + nonce, stockés en session, puis redirection
app.get('/login/:idp', (req, res) => {
  const client = clients[req.params.idp];
  const code_verifier = generators.codeVerifier();
  const code_challenge = generators.codeChallenge(code_verifier);
  const state = generators.state();
  const nonce = generators.nonce();
  req.session.oidc = { idp: req.params.idp, code_verifier, state, nonce };
  res.redirect(client.authorizationUrl({
    scope: 'openid email profile',
    code_challenge, code_challenge_method: 'S256', state, nonce,
  }));
});

// 3) Callback : openid-client vérifie state et VALIDE l'ID token (signature/iss/aud/exp/nonce)
app.get('/auth/callback/:idp', async (req, res) => {
  const client = clients[req.params.idp];
  const { code_verifier, state, nonce } = req.session.oidc || {};
  const params = client.callbackParams(req);
  const tokenSet = await client.callback(
    client.metadata.redirect_uris[0], params,
    { code_verifier, state, nonce }, // tout est vérifié pour vous
  );
  const claims = tokenSet.claims(); // contenu VALIDÉ de l'ID token

  // 4) Liaison de compte par e-mail VÉRIFIÉ uniquement
  if (!claims.email || claims.email_verified === false) {
    return res.status(403).send('E-mail non vérifié par le fournisseur.');
  }
  const user = await findOrCreateUser({
    provider: req.params.idp, subject: claims.sub, email: claims.email, name: claims.name,
  });

  // 5) Session applicative (aucun token stocké côté navigateur)
  req.session.userId = user.id;
  delete req.session.oidc;
  res.redirect('/');
});

app.get('/logout', (req, res) => req.session.destroy(() => res.redirect('/')));

Versions de openid-client

Exemple en API openid-client v5. La v6 expose une API fonctionnelle différente — la logique (découverte, PKCE, validation) reste la même.

12.2 Python — Flask + Authlib

Python
# SSO OIDC avec Google et Microsoft — Python (Flask + Authlib)
# pip install Flask Authlib
import os
from flask import Flask, session, redirect, url_for, abort
from authlib.integrations.flask_client import OAuth

app = Flask(__name__)
app.secret_key = os.environ["SECRET_KEY"]
app.config.update(SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SECURE=True,
                  SESSION_COOKIE_SAMESITE="Lax")

oauth = OAuth(app)

# 1) Déclaration des fournisseurs via leur discovery document
oauth.register(
    name="google",
    server_metadata_url="https://accounts.google.com/.well-known/openid-configuration",
    client_id=os.environ["GOOGLE_CLIENT_ID"],
    client_secret=os.environ["GOOGLE_CLIENT_SECRET"],
    client_kwargs={"scope": "openid email profile"},
)
oauth.register(
    name="microsoft",
    server_metadata_url="https://login.microsoftonline.com/<tenant>/v2.0/.well-known/openid-configuration",
    client_id=os.environ["MS_CLIENT_ID"],
    client_secret=os.environ["MS_CLIENT_SECRET"],
    client_kwargs={"scope": "openid email profile"},
)

# 2) Démarrage du login : Authlib génère state + nonce + PKCE et redirige
@app.route("/login/<idp>")
def login(idp):
    client = oauth.create_client(idp) or abort(404)
    redirect_uri = url_for("callback", idp=idp, _external=True)
    return client.authorize_redirect(redirect_uri)

# 3) Callback : échange du code + validation de l'ID token par Authlib
@app.route("/auth/callback/<idp>")
def callback(idp):
    client = oauth.create_client(idp) or abort(404)
    token = client.authorize_access_token()  # vérifie le state, échange le code
    claims = token["userinfo"]  # ID token déjà validé

    # 4) Liaison par e-mail vérifié uniquement
    if not claims.get("email") or claims.get("email_verified") is False:
        abort(403, "E-mail non vérifié par le fournisseur.")
    user = find_or_create_user(provider=idp, subject=claims["sub"],
                               email=claims["email"], name=claims.get("name"))

    # 5) Session applicative (pas de tokens stockés côté navigateur)
    session["user_id"] = user.id
    return redirect("/")

@app.route("/logout")
def logout():
    session.clear()
    return redirect("/")

Annexe — Récapitulatif des endpoints

Google

Texte
Issuer    : https://accounts.google.com
Discovery : https://accounts.google.com/.well-known/openid-configuration

Microsoft Entra ID

Texte
Discovery : https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration
({tenant} = common | organizations | consumers | <tenant-id>)

Les noms de portails et écrans peuvent évoluer ; les discovery documents ci-dessus restent la source de vérité pour les endpoints, scopes et clés de chaque fournisseur.

Besoin d'un audit cybersécurité de votre intégration SSO ?

Mission MAG&Cie

Si vous voulez qu'on vérifie ensemble votre intégration SSO avant mise en production — validation tenant Microsoft, rotation des secrets, configuration cookies, journalisation, points d'audit RGPD — c'est exactement le périmètre de l'Audit de Posture Cybersécurité ou du Cyber-Audit accéléré (rapport sous 48h).

Pour aller plus loin sur la cybersécurité applicative TPE/PME, voir Audit cybersécurité TPE/PME : combien ça coûte et qu'est-ce qu'on y trouve.