This lesson puts all three protocol flows side by side so you can see how they differ. Minimal prose, heavy on diagrams. Use this as a visual reference when you need to quickly recall which protocol does what, or when you are writing a control narrative and need to describe a specific flow accurately.
The user starts at the application. The application redirects to the identity provider. The IdP authenticates the user and POSTs a signed XML assertion back through the browser. The application validates the assertion and creates a session.
Key characteristic: the browser is the transport. The IdP and SP never communicate directly. The assertion is an XML document carried via HTTP POST.
User Service Provider (SP) Identity Provider (IdP) │ │ │ │── 1. Visit app ────────────►│ │ │ │ │ │◄── 2. Redirect ─────────────│ │ │ (AuthnRequest via │ │ │ HTTP Redirect) │ │ │ │ │ │── 3. Follow redirect ──────────────────────────────────► │ │ │ │ │◄── 4. Login page ──────────────────────────────────────────│ │ │ │ │── 5. Authenticate (+ MFA) ────────────────────────────► │ │ │ │ │◄── 6. HTML form with SAMLResponse ────────────────────────│ │ (signed XML assertion) │ │ │ │ │ │── 7. Auto-POST to ACS URL ►│ │ │ │ │ │◄── 8. Session created ──────│ │ │ (user is logged in) │ │
SAML 2.0 SP-Initiated SSO: XML assertion carried through the browser via POST binding
The user clicks "Login." The application redirects to the authorization server with a PKCE code challenge. The user authenticates and consents. The authorization server redirects back with a one-time authorization code. The application exchanges the code (plus the PKCE code verifier) for tokens via a back-channel POST.
Key characteristic: the authorization code is a one-time intermediary. Tokens are never exposed to the browser URL bar. PKCE binds the code exchange to the original client.
User Client Application Authorization Server Resource API │ │ │ │ │── 1. Click Login ──────►│ │ │ │ │── 2. Generate │ │ │ │ code_verifier + challenge │ │ │ │ │ │ │◄── 3. Redirect to ───────│ │ │ │ /authorize │ │ │ │ ?code_challenge=... │ │ │ │ │ │ │ │── 4. Authenticate ──────────────────────────────────► │ │ │ + consent │ │ │ │ │ │ │ │◄── 5. Redirect ──────────────────────────────────────────│ │ │ ?code=AUTH_CODE │ │ │ │ │ │ │ │── 6. Follow redirect ──►│ │ │ │ │ │ │ │ │── 7. POST /token ──────────►│ │ │ │ code + code_verifier │ │ │ │ │ │ │ │◄── 8. Tokens ────────────────│ │ │ │ (access_token, id_token, │ │ │ │ refresh_token) │ │ │ │ │ │ │ │── 9. API call ──────────────────────────────────► │ │ │ Authorization: Bearer ... │ │ │ │ │ │ │◄── 10. Data returned ────│◄── Response ─────────────────────────────────────── │
OAuth 2.0 Authorization Code + PKCE: code exchanged for tokens via back-channel, PKCE prevents interception
No user is involved. A backend service authenticates directly with the authorization server using its client ID and secret. The authorization server returns an access token. The service uses that token to call the target API.
Key characteristic: this is the simplest flow. One request to get a token, then use the token. No browser, no redirect, no consent. This is how microservices authorize calls to each other.
Backend Service Authorization Server Target API
│ │ │
│── 1. POST /token ─────────────────►│ │
│ grant_type=client_credentials │ │
│ client_id=... │ │
│ client_secret=... │ │
│ scope=api.read │ │
│ │ │
│◄── 2. 200 OK ──────────────────────│ │
│ { access_token: "...", │ │
│ expires_in: 3600 } │ │
│ │ │
│── 3. GET /api/resource ─────────────────────────────────────► │
│ Authorization: Bearer ... │ │
│ │ │
│◄── 4. 200 OK + data ────────────────────────────────────────── │OAuth 2.0 Client Credentials: machine-to-machine, no user involved, single token request
The application gets an ID token immediately in the authorization response (proving the user's identity) and an authorization code that it exchanges for an access token and refresh token via the back channel. This combines the immediate identity confirmation of the Implicit flow with the security of the Authorization Code exchange.
Key characteristic: response_type=code id_token. The ID token arrives in the front channel (browser redirect). The access token is retrieved via the back channel (server-to-server POST). This is used when the application needs to verify the user's identity immediately at the redirect, before making the back-channel token exchange.
User Client Application Authorization Server │ │ │ │── 1. Click Login ──────►│ │ │ │ │ │◄── 2. Redirect to ───────│ │ │ /authorize │ │ │ ?response_type= │ │ │ code id_token │ │ │ &scope=openid profile │ │ │ │ │ │── 3. Authenticate ──────────────────────────────────► │ │ + consent │ │ │ │ │ │◄── 4. Redirect ──────────────────────────────────────────│ │ ?code=AUTH_CODE │ │ │ &id_token=eyJhbG... │ │ │ (ID token in fragment) │ │ │ │ │ │── 5. Follow redirect ──►│ │ │ │── Validate ID token │ │ │ (signature, nonce, aud) │ │ │ │ │ │── 6. POST /token ──────────►│ │ │ code=AUTH_CODE │ │ │ │ │ │◄── 7. Tokens ────────────────│ │ │ (access_token, │ │ │ refresh_token) │ │ │ │ │◄── 8. Logged in ─────────│ │
OIDC Hybrid Flow: ID token in front channel for immediate identity, access token via back-channel exchange
| Aspect | SAML 2.0 | OAuth 2.0 | OIDC |
|---|---|---|---|
| Purpose | Single sign-on (enterprise) | Authorization (API access) | Authentication + authorization |
| Token format | XML assertion | Opaque string or JWT (access token) | JWT (ID token) + access token |
| Transport | Browser redirect + POST | HTTPS + JSON | HTTPS + JSON |
| Token delivery | Browser carries XML via POST | Back-channel token exchange | Back-channel (or hybrid) |
| User involved? | Always | Depends on grant type | Always |
| Best for | Enterprise SSO, legacy apps | API access, M2M, delegated auth | Modern web/mobile SSO |
| Signature | XML digital signature (RSA) | JWT signature (RSA or ECDSA) | JWT signature (RSA or ECDSA) |
| Session management | SP creates local session | Token expiration + refresh | Token expiration + refresh |
| Specification age | 2005 | 2012 (RFC 6749) | 2014 |
When to use what
SAML 2.0 — Use for enterprise SSO when integrating with legacy applications that only support SAML, or when federating with organizations that have established SAML infrastructure. Most enterprise SaaS applications (Salesforce, Workday, ServiceNow) support SAML as their primary SSO protocol.
OIDC — Use for modern web applications, mobile apps, and single-page applications that need to authenticate users. OIDC with Authorization Code + PKCE is the current best practice for user-facing authentication. If you are building or assessing a new application, OIDC should be the default choice.
OAuth 2.0 Client Credentials — Use for service-to-service communication where no user is involved. Backend services calling other APIs, CI/CD pipelines requesting temporary credentials, and automated jobs all use Client Credentials.
In practice, most organizations use all three: SAML for legacy enterprise SSO, OIDC for modern applications, and OAuth Client Credentials for machine-to-machine. Your job as a GRC engineer is to verify that each is configured correctly for its use case — not to pick one protocol over the others.
These diagrams are reference material. When you are writing a control narrative about SSO, come back to the SAML diagram to describe the assertion flow accurately. When you are reviewing an API security architecture, reference the Client Credentials or Authorization Code diagrams. When an auditor asks how authentication works for a specific application, match the application to the appropriate flow diagram and walk them through it step by step.
The next lesson is a scenario-based exercise: given a real-world use case, you will choose the right protocol and flow.