Single Sign-On (SSO) lets users log in once and access multiple applications without re-entering credentials. If you've ever clicked "Sign in with Google" or logged into your company's dashboard and had access to Slack, Jira, and Gmail automatically — that's SSO in action. Two protocols dominate the SSO landscape: SAML 2.0 and OpenID Connect (OIDC).

How SSO Works (The Big Picture)

Regardless of the protocol, SSO follows a common pattern:

  • Identity Provider (IdP): The central authority that authenticates users (e.g., Okta, Azure AD, Auth0, Google Workspace).
  • Service Provider (SP) / Relying Party (RP): The application the user wants to access (your app).
  • Trust Relationship: The SP and IdP have a pre-configured trust — they've exchanged certificates or secrets ahead of time.

The user visits your app, gets redirected to the IdP, authenticates, and gets sent back with proof of identity. Your app trusts this proof because it trusts the IdP.

Single Sign-On: Login Once, Access Everything
Identity Provider Okta / Azure AD / Auth0 / Google Workspace
Login once here
👤
Access all apps below
💬SlackChat
📋JiraProjects
🚀Your AppSaaS
GmailEmail
Trust relationship Access granted

SAML 2.0 — The Enterprise Veteran

SAML (Security Assertion Markup Language) has been the backbone of enterprise SSO since 2005. It uses XML-based assertions passed between the IdP and SP.

SAML Authentication Flow

1. User visits https://app.example.com (Service Provider)
2. SP generates a SAML AuthnRequest (XML)
3. User's browser is redirected to the IdP with the AuthnRequest
4. IdP authenticates the user (login page, MFA, etc.)
5. IdP generates a SAML Response containing an Assertion
   - The Assertion includes: user identity, attributes, conditions
   - The entire Response is digitally signed with IdP's private key
6. User's browser POSTs the SAML Response back to the SP's ACS URL
7. SP validates the signature, checks conditions, extracts user info
8. SP creates a session — user is logged in
SAML 2.0 Authentication Flow
Browser / User
Service Provider(Your App)
Identity Provider(Okta / Azure AD)
1 Visit app.example.com
2 Redirect + AuthnRequest (XML)
3 Forward AuthnRequest to IdP
4 Show login page + MFA
5 User enters credentials
Validate & Sign Assertion
6 SAML Response (signed XML Assertion)
7 POST SAML Response to ACS URL
Verify signature & extract user
8 Session created — logged in! ✅

SAML Response Structure

<saml2p:Response>
  <saml2:Assertion>
    <saml2:Issuer>https://idp.example.com</saml2:Issuer>
    <ds:Signature>...digital signature...</ds:Signature>
    <saml2:Subject>
      <saml2:NameID>user@example.com</saml2:NameID>
    </saml2:Subject>
    <saml2:Conditions NotBefore="..." NotOnOrAfter="...">
      <saml2:AudienceRestriction>
        <saml2:Audience>https://app.example.com</saml2:Audience>
      </saml2:AudienceRestriction>
    </saml2:Conditions>
    <saml2:AttributeStatement>
      <saml2:Attribute Name="email">
        <saml2:AttributeValue>user@example.com</saml2:AttributeValue>
      </saml2:Attribute>
      <saml2:Attribute Name="role">
        <saml2:AttributeValue>admin</saml2:AttributeValue>
      </saml2:Attribute>
    </saml2:AttributeStatement>
  </saml2:Assertion>
</saml2p:Response>

Implementing SAML SP in Python

# Using python3-saml
from onelogin.saml2.auth import OneLogin_Saml2_Auth

def saml_login(request):
    auth = OneLogin_Saml2_Auth(request, custom_base_path=settings.SAML_FOLDER)
    return redirect(auth.login())

def saml_acs(request):
    """Assertion Consumer Service — receives the SAML Response"""
    auth = OneLogin_Saml2_Auth(request, custom_base_path=settings.SAML_FOLDER)
    auth.process_response()
    errors = auth.get_errors()

    if not errors:
        user_data = {
            'email': auth.get_nameid(),
            'attributes': auth.get_attributes(),
            'session_index': auth.get_session_index(),
        }
        # Create/update user and establish session
        create_session(user_data)
        return redirect('/dashboard')
    else:
        return HttpResponse(f'SAML Error: {errors}', status=400)

OpenID Connect (OIDC) — The Modern Standard

OIDC is built on top of OAuth 2.0 and uses JSON/JWT instead of XML. It was designed in 2014 as a simpler, more developer-friendly alternative to SAML.

OIDC Authorization Code Flow

1. User visits https://app.example.com
2. App redirects to IdP's authorization endpoint:
   GET https://idp.example.com/authorize?
     response_type=code
     &client_id=YOUR_CLIENT_ID
     &redirect_uri=https://app.example.com/callback
     &scope=openid profile email
     &state=random_csrf_token
     &nonce=random_nonce

3. User authenticates at the IdP
4. IdP redirects back with an authorization code:
   GET https://app.example.com/callback?code=AUTH_CODE&state=random_csrf_token

5. App exchanges the code for tokens (server-to-server):
   POST https://idp.example.com/token
   {
     "grant_type": "authorization_code",
     "code": "AUTH_CODE",
     "redirect_uri": "https://app.example.com/callback",
     "client_id": "YOUR_CLIENT_ID",
     "client_secret": "YOUR_CLIENT_SECRET"
   }

6. IdP returns tokens:
   {
     "access_token": "eyJ...",
     "id_token": "eyJ...",      // Contains user identity
     "refresh_token": "eyJ...",
     "token_type": "Bearer",
     "expires_in": 3600
   }

7. App validates the id_token JWT and extracts user info
OIDC Authorization Code Flow
Browser / User
Your App(Relying Party)
Identity Provider(OIDC Server)
1 Visit app
2 Redirect to /authorize
3 /authorize?response_type=code&scope=openid
4 Login page
5 User authenticates
6 Redirect to /callback?code=AUTH_CODE
7 Forward code to app server
Back Channel (Server-to-Server)
8 Exchange code for tokens
9 access_token + id_token (JWT)
Validate JWT & extract user info
10 Session created — logged in! ✅

The ID Token

The key differentiator of OIDC is the ID Token — a JWT containing the authenticated user's identity:

JSON Web Token (JWT) Structure — Hover to Explore
Header eyJhbGciOiJSUzI1NiJ9 {"alg": "RS256", "typ": "JWT"}
.
Payload (Claims) eyJzdWIiOiIxMjM0NTY3... {"sub", "email", "name", "exp", ...}
.
Signature SflKxwRJSMeKKF2QT4fw... HMAC-SHA256 or RSA signature
eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyLXV1aWQiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20ifQ.SflKxwRJSMeKKF2QT4fwpM
// Decoded ID Token payload
{
  "iss": "https://idp.example.com",
  "sub": "user-uuid-12345",
  "aud": "YOUR_CLIENT_ID",
  "exp": 1712345678,
  "iat": 1712342078,
  "nonce": "random_nonce",
  "email": "user@example.com",
  "name": "Jane Developer",
  "picture": "https://example.com/photo.jpg",
  "email_verified": true
}

SAML vs OIDC — When to Use Which

  • Use SAML when: Integrating with enterprise IdPs (Okta, Azure AD, ADFS), legacy systems require it, or your customers' IT teams expect SAML support. Most enterprise B2B SaaS products need SAML.
  • Use OIDC when: Building modern web/mobile apps, using social login (Google, GitHub, Apple), building consumer-facing products, or when you want simpler implementation with JWTs.
  • Support both when: Building a B2B SaaS product that serves both enterprise and smaller customers. Most identity platforms (Auth0, Okta) can act as a bridge, accepting SAML from enterprise IdPs and exposing OIDC to your app.

Key Differences at a Glance

Feature              SAML 2.0              OIDC
──────────────────   ──────────────────    ──────────────────
Data Format          XML                   JSON / JWT
Transport            HTTP POST/Redirect    HTTP GET/POST
Token Type           XML Assertion         JWT (ID Token)
Year Introduced      2005                  2014
Best For             Enterprise SSO        Modern apps, mobile
Complexity           High                  Medium
Mobile Support       Poor                  Excellent
Discovery            Manual config         .well-known endpoint
Standard Body        OASIS                 OpenID Foundation
SAML 2.0 vs OpenID Connect — At a Glance
SAML 2.0
📄Data FormatXML
📦Token TypeXML Assertion
📅Since2005
🏢Best ForEnterprise SSO
📱MobilePoor
ComplexityHigh
🔍DiscoveryManual config
VS
OpenID Connect
📄Data FormatJSON / JWT
📦Token TypeJWT (ID Token)
📅Since2014
🏢Best ForModern apps
📱MobileExcellent
ComplexityMedium
🔍Discovery.well-known
Which Protocol Should You Use?
What are you building?
Enterprise B2B SaaS?
Use SAML(+ OIDC optional)
Both enterprise + consumer?
Support Both(Auth0/Okta as bridge)
Consumer / Mobile app?
Use OIDC(simpler, JWT-based)

Security Best Practices for Both

  • Always validate signatures: Never trust assertions or tokens without verifying the cryptographic signature.
  • Check timestamps: Validate NotBefore, NotOnOrAfter (SAML) and exp, iat (OIDC) to prevent replay attacks.
  • Verify audience: Ensure the assertion/token was intended for your application.
  • Use HTTPS everywhere: Tokens and assertions must only travel over TLS.
  • Implement proper session management: Support single logout (SLO) and session timeouts.
  • Store secrets securely: Client secrets and private keys belong in vaults, not config files.

SSO is no longer optional for serious applications. Whether you choose SAML, OIDC, or both, understanding these protocols deeply will help you build secure, user-friendly authentication that scales with your product.