Skip to main content
Cloud & AI Hub
Browse
Glossary AI Directory Playgrounds Models Prompts Explainers Strategy Matrix Benchmark Decoder
intermediate 9 mins Read

Understanding Single Sign-On Authentication Flows

How SAML 2.0 and OpenID Connect enable users to authenticate once across multiple applications using identity provider assertions.

Introduction

Single Sign-On (SSO) allows users to authenticate once — with their company’s identity provider (Okta, Azure Entra ID, Google Workspace) — and then access multiple applications without re-entering credentials. From a user’s perspective, they log in to one place and everything else “just works.” From a security perspective, SSO centralizes authentication: credentials are managed in one place, MFA is enforced uniformly, and account deprovisioning (when an employee leaves) immediately revokes access to all connected applications.

Two protocols dominate enterprise SSO: SAML 2.0 (XML-based, older, common in enterprise SaaS) and OpenID Connect (OIDC) (JSON/JWT-based, modern, preferred for web and mobile apps).

SAML 2.0 SSO Flow (SP-Initiated)

flowchart TD
    A["1. User Accesses Service Provider"]
    B["2. SP Redirects to Identity Provider"]
    C["3. User Authenticates with IdP"]
    D["4. IdP Posts SAML Assertion to SP"]
    E["5. SP Validates and Creates Session"]
    A --> B
    B --> C
    C --> D
    D --> E

Step 1: User Accesses Service Provider

User navigates to: https://app.example.com/dashboard (Service Provider)
SP checks: No active session
SP generates: AuthnRequest XML

Step 2: SP Redirects to Identity Provider

HTTP 302 Redirect to:
https://sso.company.com/saml/sso?
  SAMLRequest=base64(deflate(AuthnRequest_XML))&
  RelayState=https://app.example.com/dashboard&
  SigAlg=http://www.w3.org/2001/04/xmldsig-more#rsa-sha256&
  Signature=...

AuthnRequest XML (decoded):
<samlp:AuthnRequest
  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
  ID="_abc123"
  Version="2.0"
  IssueInstant="2024-03-15T14:00:00Z"
  Destination="https://sso.company.com/saml/sso"
  AssertionConsumerServiceURL="https://app.example.com/saml/acs">
  <saml:Issuer>https://app.example.com/saml/metadata</saml:Issuer>
</samlp:AuthnRequest>

Step 3: User Authenticates with IdP

User sees: Company SSO login page (Okta/Entra ID)
If already logged in via prior SSO session: skip (no password required)
If not: Enter corporate credentials + MFA
IdP validates credentials, checks user is allowed to access this SP

Step 4: IdP Posts SAML Assertion to SP

<!-- IdP POSTs this to app.example.com/saml/acs -->
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
  <saml:Assertion>
    <saml:Issuer>https://sso.company.com</saml:Issuer>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
        [email protected]
      </saml:NameID>
    </saml:Subject>
    <saml:Conditions
      NotBefore="2024-03-15T14:00:00Z"
      NotOnOrAfter="2024-03-15T14:05:00Z">  <!-- 5-minute validity window -->
      <saml:AudienceRestriction>
        <saml:Audience>https://app.example.com/saml/metadata</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AttributeStatement>
      <saml:Attribute Name="email">
        <saml:AttributeValue>[email protected]</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="groups">
        <saml:AttributeValue>engineering</saml:AttributeValue>
        <saml:AttributeValue>admin</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
    <saml:Signature><!-- XML Digital Signature (RSA-SHA256) --></saml:Signature>
  </saml:Assertion>
</samlp:Response>

Step 5: SP Validates and Creates Session

from onelogin.saml2.auth import OneLogin_Saml2_Auth

def saml_acs(request):
    auth = OneLogin_Saml2_Auth(request, custom_base_path="/saml/settings")
    auth.process_response()
    
    if auth.is_authenticated():
        attributes = auth.get_attributes()
        email = attributes.get('email', [None])[0]
        groups = attributes.get('groups', [])
        
        # Create application session
        session['user'] = email
        session['groups'] = groups
        return redirect(session.get('RelayState', '/dashboard'))
    else:
        errors = auth.get_errors()
        return render_error(errors)

OpenID Connect (OIDC) SSO Flow

OIDC is OAuth 2.0 + an identity layer — the same flow as OAuth but with an additional ID token (JWT) containing user identity claims:

# Using authlib for OIDC in Flask
from authlib.integrations.flask_client import OAuth

oauth = OAuth(app)
oauth.register(
    name='company_sso',
    server_metadata_url='https://sso.company.com/.well-known/openid-configuration',
    client_id='CLIENT_ID',
    client_secret='CLIENT_SECRET',
    client_kwargs={'scope': 'openid email profile groups'}
)

@app.route('/login')
def login():
    redirect_uri = url_for('authorize', _external=True)
    return oauth.company_sso.authorize_redirect(redirect_uri)

@app.route('/authorize')
def authorize():
    token = oauth.company_sso.authorize_access_token()
    user_info = token['userinfo']  # Decoded ID token claims
    session['user'] = user_info['email']
    session['groups'] = user_info.get('groups', [])
    return redirect('/')

Key Takeaways

  • SAML 2.0 uses XML assertions and browser POST — common in enterprise SaaS (Salesforce, Workday). Complex but mature.
  • OIDC uses JWT ID tokens and JSON — preferred for modern web/mobile apps. Simpler, more developer-friendly.
  • SSO provides centralized authentication — MFA enforcement, session policies, and deprovisioning apply uniformly across all connected apps.
  • Audience restriction in SAML / audience claim in OIDC prevents an assertion/token issued for App A from being replayed at App B.
  • IdPs maintain an SSO session cookie — subsequent SP logins skip credential entry if the IdP session is valid (the “single” in single sign-on).

Historical figures, architectures, and capabilities are for informational purposes only. Not technical, professional, legal, or financial advice. Sources: Research papers, developer documentation.