Le premier gros client qui signe un contrat demandera l'authentification unique avec son fournisseur d'identité, et très souvent, cela veut dire SAML 2.0. La norme date de 2005, elle fait transiter du XML via des redirections et des envois de formulaires dans le navigateur, et ses messages d'erreur vont du vague au silencieux. La plupart des bugs SAML, y compris de graves failles de sécurité, viennent du fait qu'on ne sait pas exactement quel message va où, ni ce que le fournisseur de services doit vérifier.
Cet article déroule le flux initié par le SP message par message avec un diagramme de séquence, puis la variante initiée par l'IdP et ses risques, l'anatomie d'une réponse SAML, la liste de vérifications pour votre application, les métadonnées et la rotation des certificats, et la comparaison entre SAML et OpenID Connect.
Les trois parties
| Partie | En termes SAML | Exemples |
|---|---|---|
| Le navigateur de l'utilisateur | Agent utilisateur | N'importe quel navigateur |
| Votre application | Fournisseur de services (SP) | Votre application SaaS |
| Le système de connexion du client | Fournisseur d'identité (IdP) | Microsoft Entra ID, Okta, Google Workspace, AD FS |
Dans le profil courant Web Browser SSO, le SP et l'IdP ne se parlent jamais directement. Chaque message passe par le navigateur, sous forme de redirection ou de formulaire soumis automatiquement. Ce qu'ils partagent, c'est une configuration, échangée une fois sous forme de métadonnées : l'entity ID de chaque côté, l'URL de connexion de l'IdP, l'URL de l'Assertion Consumer Service (ACS) du SP et le certificat de signature de l'IdP.
Le flux initié par le SP, étape par étape
L'utilisateur commence sur votre application :
- L'utilisateur ouvre
https://app.example.com/dashboardsans session. - Votre application crée un
AuthnRequestavec un identifiant unique, son entity ID et son URL ACS, stocke l'identifiant dans l'état de connexion en attente et redirige le navigateur vers l'IdP. Avec le binding HTTP-Redirect, la requête voyage dans la query string sous le nomSAMLRequest(compressée avec deflate, encodée en base64), à côté d'une valeurRelayStatequi mémorise où l'utilisateur voulait aller. - L'IdP authentifie l'utilisateur : mot de passe et MFA, ou une session IdP existante, auquel cas l'utilisateur ne voit rien.
- L'IdP renvoie une page HTML avec un formulaire qui poste une
SAMLResponsesignée et le mêmeRelayStatevers votre URL ACS. C'est le binding HTTP-POST, et un petit script soumet le formulaire automatiquement. - Votre application valide la réponse, crée son propre cookie de session et redirige l'utilisateur vers la page enregistrée dans
RelayState.
Dès lors, c'est la session propre à votre application qui décide de l'identité de l'utilisateur. SAML n'intervient à nouveau qu'à l'expiration de cette session.
La spécification des bindings limite RelayState à 80 octets ; stockez donc la vraie URL de retour côté serveur et envoyez une clé courte.
Ce que contient une réponse SAML
Réduite aux parties que lit votre application, une réponse ressemble à ceci :
<samlp:Response ID="_r81c" InResponseTo="_req42" Destination="https://app.example.com/saml/acs">
<saml:Assertion ID="_a77e">
<saml:Issuer>https://idp.customer.com/entity</saml:Issuer>
<ds:Signature>…</ds:Signature>
<saml:Subject>
<saml:NameID>ana@customer.com</saml:NameID>
<saml:SubjectConfirmationData InResponseTo="_req42"
Recipient="https://app.example.com/saml/acs" NotOnOrAfter="2026-11-02T09:05:00Z"/>
</saml:Subject>
<saml:Conditions NotBefore="2026-11-02T08:59:30Z" NotOnOrAfter="2026-11-02T09:05:00Z">
<saml:AudienceRestriction><saml:Audience>https://app.example.com</saml:Audience></saml:AudienceRestriction>
</saml:Conditions>
<saml:AttributeStatement>…email, name, groups…</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
L'assertion est la déclaration signée : qui est l'utilisateur (NameID), qui l'affirme (Issuer), pour qui (Audience), pour combien de temps, et en réponse à quelle requête (InResponseTo).
La liste de vérifications
C'est à votre point de terminaison ACS que la sécurité SAML réussit ou échoue. Il doit :
- Vérifier la signature avec le certificat issu des métadonnées de l'IdP, jamais avec un certificat intégré au message lui-même.
- Ne lire que ce que couvre la signature. Les attaques par XML signature wrapping insèrent une seconde assertion, non signée, en espérant que le code vérifie un élément et en lise un autre. Des chercheurs ont trouvé cette faille dans 11 des 14 principaux frameworks SAML en 2012, et elle revient sans cesse : ruby-saml a corrigé en 2024 un contournement de signature noté CVSS 10.0 (CVE-2024-45409), puis en 2025 deux contournements par divergence de parseurs (CVE-2025-25291 et CVE-2025-25292).
- Vérifier
Issuerpar rapport à l'entity ID de l'IdP de ce client. - Vérifier
Audiencepar rapport à votre propre entity ID. - Vérifier
DestinationetRecipientpar rapport à votre URL ACS. - Vérifier
NotBeforeetNotOnOrAfteravec une tolérance d'une à deux minutes pour le décalage d'horloge. - Faire correspondre
InResponseToà un identifiant d'AuthnRequestque vous avez émis pour ce navigateur et pas encore utilisé. - Rejeter les rejeux en mémorisant les identifiants d'assertion jusqu'à leur expiration.
- Traiter
RelayStatecomme non fiable. Ne redirigez que vers des chemins relatifs ou une liste d'autorisation, sinon vous avez une redirection ouverte.
La leçon de dix ans de vulnérabilités SAML : utilisez une bibliothèque maintenue, figez sa version, appliquez vite ses correctifs, et n'écrivez jamais votre propre vérification de signature XML.
Le SSO initié par l'IdP, et pourquoi il est plus risqué
Dans le flux initié par l'IdP, l'utilisateur commence chez l'IdP, en général en cliquant sur la tuile de votre application dans un tableau de bord comme le portail Okta ou Microsoft My Apps. L'IdP poste une réponse non sollicitée vers votre URL ACS. Il n'y a pas eu d'AuthnRequest, donc pas d'InResponseTo à faire correspondre.
| Initié par le SP | Initié par l'IdP | |
|---|---|---|
| Point de départ | Votre application | Le portail de l'IdP |
AuthnRequest |
Oui | Non |
Vérification de InResponseTo |
Oui | Impossible |
| Protection contre le CSRF de connexion | Intégrée | Demande un soin supplémentaire |
| Liens profonds | Via RelayState |
Arrive en général sur une page par défaut |
Sans InResponseTo, un attaquant qui obtient une réponse valide, ou qui amène le navigateur d'une victime à en poster une, peut connecter la victime au compte de l'attaquant ou rejouer une réponse volée pendant sa durée de validité. Si les clients ont besoin de tuiles dans leur tableau de bord, le modèle le plus sûr est une tuile qui ouvre l'URL de connexion de votre application, laquelle lance ensuite un flux normal initié par le SP. Si vous devez accepter des réponses non sollicitées, gardez une validité courte, imposez des identifiants d'assertion à usage unique et autorisez-le client par client plutôt que globalement.
Métadonnées, certificats et configurations multi-tenant
L'IdP de chaque client est une relation de confiance distincte. Stockez par tenant : l'entity ID de l'IdP, l'URL de connexion, les certificats de signature et le mapping des attributs. Le diagramme d'architecture SaaS multi-tenant montre où vit généralement cette configuration par tenant.
Les certificats de signature expirent, et un certificat expiré ou renouvelé est la cause la plus fréquente d'un client entier soudain incapable de se connecter. Acceptez deux certificats par IdP pendant une rotation, lisez régulièrement l'URL de métadonnées de l'IdP s'il en publie une, et déclenchez une alerte des semaines avant l'expiration.
SAML authentifie ; il ne synchronise pas votre liste d'utilisateurs. Créer des comptes à la première connexion est facile, mais retirer l'accès quand quelqu'un part demande du provisioning, en général SCIM 2.0 (RFC 7644). Sans cela, un employé désactivé garde toute session déjà émise par votre application.
SAML ou OpenID Connect ?
| SAML 2.0 | OpenID Connect | |
|---|---|---|
| Format | Assertions XML avec signatures XML | JSON, avec des ID tokens JWT |
| Transport | Redirections et envois de formulaires dans le navigateur | Redirections plus une requête de jeton en back-channel |
| Applications mobiles et SPA | Malcommode | Conçu pour elles |
| Usage typique | SSO d'entreprise vers des applications SaaS | Connexion grand public, API, SSO d'entreprise moderne |
Les nouvelles applications peuvent commencer par OpenID Connect, mais les clients entreprise continueront de demander SAML ; la plupart des produits B2B prennent donc en charge les deux. Le diagramme de flux OAuth 2.0 couvre le protocole sur lequel s'appuie OpenID Connect.
Le diagramme SAML SSO
Contenu du diagramme
- User
- Browser
- Service provider (your app)
- Identity provider
- no IdP session yet
- 1. Open the app
- 2. GET /dashboard (no session)
- 3. 302 to IdP: SAMLRequest + RelayState
- 4. GET /sso?SAMLRequest=…&RelayState=… (HTTP-Redirect)
- 5. Login page
- 6. Password + MFA
- 7. HTML form: signed SAMLResponse + RelayState
- 8. POST /saml/acs (HTTP-POST, auto-submit)
- 9. 302 /dashboard + session cookie
- 10. GET /dashboard (cookie)
- 11. 200 OK
Comment le lire :
- Quatre participants. L'utilisateur, le navigateur, votre application en tant que fournisseur de services et le fournisseur d'identité. Le temps s'écoule vers le bas.
- La redirection transporte l'
AuthnRequestet leRelayStatede votre application vers l'IdP, à travers le navigateur. - Le fragment optionnel est l'étape de connexion. Avec une session IdP existante, elle est sautée et l'utilisateur ne voit qu'une redirection rapide.
- L'envoi de formulaire livre la
SAMLResponsesignée à l'URL ACS. Votre application la valide et pose son propre cookie de session. - Le bloc Markdown liste les vérifications que doit faire le point de terminaison ACS.
Dessiner des flux SSO qui aident au débogage
- Dessinez le navigateur comme un participant à part entière. SAML est un protocole front-channel ; cacher le navigateur, c'est cacher où les messages peuvent être interceptés ou rejoués.
- Indiquez le binding sur chaque flèche : redirection ou POST, et le nom du paramètre. La plupart des erreurs de configuration sont une mauvaise URL ou un mauvais binding.
- Mettez les identifiants sur les messages. Montrer que
InResponseToreprend l'identifiant de la requête explique pourquoi on le vérifie. - Dessinez le flux initié par l'IdP à part, avec son risque indiqué, plutôt que comme une branche du diagramme principal.
L'exemple de diagramme de séquence approfondit les participants, les fragments et les étiquettes, et le diagramme d'architecture zero trust montre où se place le fournisseur d'identité dans un modèle d'accès plus large.
Le construire dans Archboard
- Connectez-vous avec Google ou GitHub et créez un diagramme.
- Ajoutez un Acteur du pack Séquence pour l'utilisateur, puis trois nœuds Ligne de vie : Browser, Service provider et Identity provider.
- Dessinez les messages de haut en bas comme des arêtes entre les lignes de vie : la première requête, la redirection avec
SAMLRequestetRelayState, la requête vers l'IdP, le formulaire avecSAMLResponse, le POST vers l'URL ACS et la redirection finale avec le cookie de session. - Ajoutez un Fragment combiné du pack Séquence avec l'opérateur
optautour de l'étape de connexion et de MFA. - Ajoutez un bloc Markdown du pack Base avec la liste de vérifications.
L'exemple utilise 6 nœuds de diagramme et reste dans les limites de l'offre Free.
FAQ
Quelle est la différence entre un SSO initié par le SP et un SSO initié par l'IdP ? La connexion initiée par le SP commence sur votre application, qui envoie un AuthnRequest à l'IdP. La connexion initiée par l'IdP commence dans le portail de l'IdP, qui poste une réponse non sollicitée vers votre application. La seconde n'a pas de requête à faire correspondre, ce qui affaiblit la protection contre les rejeux et le CSRF de connexion.
Qu'est-ce qu'une URL ACS ? L'URL de l'Assertion Consumer Service est le point de terminaison de votre application qui reçoit la réponse SAML par HTTP POST. Elle est configurée dans l'IdP et doit correspondre aux valeurs Destination et Recipient de chaque réponse.
À quoi sert RelayState ? Il transporte l'endroit que l'utilisateur voulait atteindre, pour que votre application l'y envoie après la connexion. Il est limité à 80 octets et constitue une entrée non fiable : utilisez-le comme clé vers un état côté serveur ou validez-le par rapport à une liste d'autorisation.
SAML est-il dépassé ? Il est plus ancien qu'OpenID Connect et plus difficile à implémenter de façon sûre, mais il reste la norme qu'attendent de nombreux fournisseurs d'identité et acheteurs en entreprise. La plupart des produits B2B prennent en charge les deux.
SAML supprime-t-il les utilisateurs qui quittent l'entreprise ? Non. SAML n'authentifie qu'à la connexion. Le déprovisionnement demande SCIM ou une autre intégration de provisioning, ainsi que des durées de session raisonnables dans votre application.