{"id":609,"date":"2026-02-16T19:49:11","date_gmt":"2026-02-16T19:49:11","guid":{"rendered":"https:\/\/blog.asambe.ai\/index.php\/2026\/02\/16\/how-single-sign-on-works-saml-vs-oidc-step-by-step\/"},"modified":"2026-02-16T19:49:13","modified_gmt":"2026-02-16T19:49:13","slug":"how-single-sign-on-works-saml-vs-oidc-step-by-step","status":"publish","type":"post","link":"https:\/\/blog.asambe.ai\/index.php\/2026\/02\/16\/how-single-sign-on-works-saml-vs-oidc-step-by-step\/","title":{"rendered":"How Single Sign-On Works SAML vs OIDC Step-by-Step"},"content":{"rendered":"<p>Ever wondered how a single click can log you into multiple apps without typing your password over and over? That convenience is powered by Single Sign-On (SSO). In this guide, we\u2019ll demystify how SSO works and walk through the two most common protocols\u2014SAML and OpenID Connect (OIDC)\u2014step by step. By the end, you\u2019ll understand the moving parts, common pitfalls, and which approach fits your use case.<\/p>\n<p>Whether you\u2019re evaluating an identity provider, integrating SSO into your product, or simply curious about what happens behind the scenes, this professional, plain-language walkthrough has you covered.<\/p>\n<h2>Table of Contents<\/h2>\n<ul>\n<li><a href=\"#what-is-sso\">What Is Single Sign-On?<\/a><\/li>\n<li><a href=\"#saml-vs-oidc\">SAML vs. OIDC at a Glance<\/a><\/li>\n<li><a href=\"#how-saml-works-step-by-step\">How SAML SSO Works: Step-by-Step<\/a><\/li>\n<li><a href=\"#how-oidc-works-step-by-step\">How OIDC SSO Works: Step-by-Step<\/a><\/li>\n<li><a href=\"#security-considerations\">Security Considerations and Best Practices<\/a><\/li>\n<li><a href=\"#implementation-tips\">Implementation Tips and Tooling<\/a><\/li>\n<li><a href=\"#common-pitfalls\">Common Pitfalls and Troubleshooting<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<li><a href=\"#frequently-asked-questions\">Frequently Asked Questions<\/a><\/li>\n<\/ul>\n<h2 id=\"what-is-sso\">What Is Single Sign-On?<\/h2>\n<p>Single Sign-On lets users authenticate once and access multiple independent applications without re-entering credentials. Instead of each app storing and checking passwords, a trusted Identity Provider (IdP) verifies the user and securely shares that proof of identity with other apps.<\/p>\n<h3>Key actors<\/h3>\n<ul>\n<li><strong>User (Browser\/App):<\/strong> The person trying to sign in.<\/li>\n<li><strong>Service Provider (SP) \/ Relying Party (RP):<\/strong> The application the user wants to access.<\/li>\n<li><strong>Identity Provider (IdP) \/ Authorization Server (AS):<\/strong> The authority that authenticates the user and issues identity information.<\/li>\n<\/ul>\n<h3>Why organizations use SSO<\/h3>\n<ul>\n<li><strong>Better user experience:<\/strong> Fewer prompts and faster access.<\/li>\n<li><strong>Improved security:<\/strong> Centralized policies, MFA, and fewer passwords to manage.<\/li>\n<li><strong>Reduced IT overhead:<\/strong> Easier provisioning, deprovisioning, and compliance.<\/li>\n<\/ul>\n<h2 id=\"saml-vs-oidc\">SAML vs. OIDC at a Glance<\/h2>\n<p>SSO is a concept; SAML and OIDC are the protocols that make it work. They share the same goal but differ in format, ecosystem, and typical use cases.<\/p>\n<h3>Core differences<\/h3>\n<ul>\n<li><strong>Data format:<\/strong> SAML uses XML assertions; OIDC uses JSON Web Tokens (JWT) for ID tokens.<\/li>\n<li><strong>Transport:<\/strong> SAML commonly uses browser redirects and POSTs; OIDC is built on OAuth 2.0 authorization flows with redirects and token exchanges.<\/li>\n<li><strong>Use cases:<\/strong> SAML is prevalent in enterprise SSO for web apps; OIDC shines for modern web, SPA, and mobile apps.<\/li>\n<li><strong>Developer ergonomics:<\/strong> OIDC\u2019s JSON and JWT tooling is typically simpler for modern stacks.<\/li>\n<\/ul>\n<p>In short, choose SAML for legacy or enterprise integrations that expect it, and favor <em>OIDC (Authorization Code with PKCE)<\/em> for new apps, SPAs, and mobile.<\/p>\n<h2 id=\"how-saml-works-step-by-step\">How SAML SSO Works: Step-by-Step<\/h2>\n<p>SAML (Security Assertion Markup Language) enables an IdP to assert a user\u2019s identity to an SP using signed XML messages. Here\u2019s a high-level path for a typical browser-based login.<\/p>\n<h3>Actors &#038; artifacts<\/h3>\n<ul>\n<li><strong>SP:<\/strong> The application that wants to know who the user is.<\/li>\n<li><strong>IdP:<\/strong> The identity authority.<\/li>\n<li><strong>SAML Request\/Response:<\/strong> XML messages. The response includes the <em>Assertion<\/em> with user identity and attributes.<\/li>\n<li><strong>Bindings:<\/strong> Commonly Redirect (GET) for requests and POST for responses.<\/li>\n<\/ul>\n<h3>SP-initiated SSO flow<\/h3>\n<ol>\n<li><strong>User accesses the app (SP):<\/strong> The user visits a protected page. The SP detects no session and starts SSO.<\/li>\n<li><strong>SP crafts SAML AuthnRequest:<\/strong> The SP generates an AuthnRequest (often deflated and base64-encoded), includes a <em>RelayState<\/em> to remember where to return the user, and signs it if required.<\/li>\n<li><strong>Browser redirects to IdP:<\/strong> The user\u2019s browser is redirected to the IdP\u2019s SSO endpoint with the AuthnRequest (commonly via HTTP Redirect binding).<\/li>\n<li><strong>IdP authenticates the user:<\/strong> The IdP prompts for credentials and may enforce MFA or policy checks.<\/li>\n<li><strong>IdP issues SAML Response:<\/strong> After success, the IdP creates a signed SAML Response containing an Assertion with user identity (NameID) and attributes (e.g., email, role).<\/li>\n<li><strong>Browser POSTs response to SP:<\/strong> The IdP instructs the browser to POST the base64-encoded SAML Response (and RelayState) to the SP\u2019s ACS (Assertion Consumer Service) URL.<\/li>\n<li><strong>SP validates the response:<\/strong> The SP checks XML signature, certificate, issuer, audience, conditions (time windows), and <em>InResponseTo<\/em> to prevent replay or mismatch. If valid, it creates an app session.<\/li>\n<li><strong>User is redirected to target:<\/strong> The SP uses RelayState to restore the user\u2019s original destination, now authenticated.<\/li>\n<\/ol>\n<h3>IdP-initiated SSO (optional)<\/h3>\n<p>The user starts at the IdP\u2019s application portal and selects the SP. The IdP sends a signed SAML Response directly to the SP\u2019s ACS via the browser. It\u2019s simpler but lacks the SP\u2019s original AuthnRequest correlation, so handle replay protection and audience checks carefully.<\/p>\n<h3>Logout (SLO)<\/h3>\n<p>SAML Single Logout can log the user out from multiple apps via front-channel (browser redirects) or back-channel (server-to-server). In practice, SLO can be brittle across heterogeneous apps; many organizations rely on local logout plus short sessions.<\/p>\n<h3>What SAML conveys<\/h3>\n<ul>\n<li><strong>Authentication:<\/strong> Proof the user authenticated at the IdP, with context (e.g., MFA).<\/li>\n<li><strong>Attributes:<\/strong> Claims such as email, groups, or roles for authorization decisions.<\/li>\n<li><strong>Conditions:<\/strong> Time-bound constraints and audience restrictions to prevent misuse.<\/li>\n<\/ul>\n<h2 id=\"how-oidc-works-step-by-step\">How OIDC SSO Works: Step-by-Step<\/h2>\n<p>OpenID Connect layers identity on top of OAuth 2.0. It provides an <em>ID token<\/em> (usually a JWT) that asserts who the user is, plus access and refresh tokens for APIs when needed.<\/p>\n<h3>Actors &#038; tokens<\/h3>\n<ul>\n<li><strong>RP (Client App):<\/strong> The application seeking identity info.<\/li>\n<li><strong>Authorization Server \/ OpenID Provider (OP):<\/strong> The IdP issuing tokens.<\/li>\n<li><strong>ID token:<\/strong> A signed JWT containing user identity and claims (iss, aud, exp, iat, sub, nonce, etc.).<\/li>\n<li><strong>Access token (optional):<\/strong> For calling APIs; may be JWT or opaque.<\/li>\n<li><strong>Refresh token (optional):<\/strong> To obtain new tokens without user re-login (use with care).<\/li>\n<\/ul>\n<h3>Recommended flow: Authorization Code with PKCE<\/h3>\n<ol>\n<li><strong>User starts sign-in at RP:<\/strong> The RP detects no session and redirects the browser to the OP\u2019s authorization endpoint with parameters: response_type=code, client_id, redirect_uri, scope (e.g., openid email profile), <em>state<\/em> (CSRF protection), and <em>nonce<\/em> (replay protection). For public clients (SPAs, mobile), include <strong>code_challenge<\/strong> and <strong>code_challenge_method<\/strong> (PKCE).<\/li>\n<li><strong>User authenticates at OP:<\/strong> The OP prompts for credentials and may request consent or MFA. On success, it redirects the browser back to the RP\u2019s redirect_uri with an authorization <strong>code<\/strong> and the original state.<\/li>\n<li><strong>RP validates state:<\/strong> The RP must verify the returned <em>state<\/em> matches the request to prevent CSRF.<\/li>\n<li><strong>Token exchange (back channel):<\/strong> The RP sends the code to the OP\u2019s token endpoint (server-to-server) including client authentication (or PKCE <em>code_verifier<\/em> for public clients). The OP returns an <strong>ID token<\/strong> (JWT) and, optionally, <strong>access token<\/strong> and <strong>refresh token<\/strong>.<\/li>\n<li><strong>Validate ID token:<\/strong> The RP verifies the JWT signature against the OP\u2019s JWKS, checks issuer (iss), audience (aud), expiration (exp), and confirms the <em>nonce<\/em> if used. This step is crucial to trust the identity.<\/li>\n<li><strong>Create app session:<\/strong> After validation, the RP establishes a session (e.g., secure, HTTP-only cookie) and optionally fetches more claims from the <em>UserInfo<\/em> endpoint using the access token.<\/li>\n<li><strong>Use access token for APIs:<\/strong> If your app calls a resource server, include the access token in API requests (e.g., Authorization: Bearer &#8230;). Verify tokens server-side and enforce scopes.<\/li>\n<li><strong>Session &#038; logout:<\/strong> The RP can manage session lifetimes and participate in OIDC front-channel or back-channel logout. For SPAs, use silent re-auth or refresh tokens with strong controls.<\/li>\n<\/ol>\n<h3>Why PKCE matters<\/h3>\n<p><strong>PKCE<\/strong> protects the authorization code from interception attacks by binding it to a secret (code_verifier) known only to the client. For public clients like SPAs and mobile apps, PKCE is a <strong>must<\/strong>.<\/p>\n<h3>Scopes and claims<\/h3>\n<ul>\n<li><strong>Scopes:<\/strong> openid (required), plus optional scopes like email, profile, and offline_access (for refresh tokens).<\/li>\n<li><strong>Claims:<\/strong> Standard claims (sub, name, email) and custom claims for app-specific authorization.<\/li>\n<\/ul>\n<h2 id=\"security-considerations\">Security Considerations and Best Practices<\/h2>\n<p>SSO centralizes trust. Treat every step with care\u2014especially redirects and token handling.<\/p>\n<ul>\n<li><strong>Always use HTTPS:<\/strong> Protect tokens, assertions, and sessions in transit.<\/li>\n<li><strong>Validate signatures and issuers:<\/strong> For SAML, verify XML signatures and metadata. For OIDC, validate JWT signatures and issuer\/audience claims.<\/li>\n<li><strong>Use state and nonce:<\/strong> Prevent CSRF and replay attacks in OIDC with strong, random values.<\/li>\n<li><strong>Prefer Authorization Code + PKCE for OIDC:<\/strong> Avoid implicit flows; they expose tokens in the browser URL.<\/li>\n<li><strong>Secure session cookies:<\/strong> Use HttpOnly, Secure, SameSite where appropriate. Keep sessions short and rotate when privilege changes.<\/li>\n<li><strong>Clock synchronization:<\/strong> Token validation relies on time. Keep servers\u2019 clocks accurate to avoid false expirations.<\/li>\n<li><strong>Token storage:<\/strong> Avoid storing tokens in localStorage. Favor secure cookies or in-memory storage for SPAs; never expose refresh tokens to XSS.<\/li>\n<li><strong>Metadata and JWKS pinning:<\/strong> Fetch IdP metadata\/JWKS over TLS, cache appropriately, and handle key rotation gracefully.<\/li>\n<li><strong>Enforce MFA and risk policies:<\/strong> Step-up authentication for sensitive actions, device posture checks where needed.<\/li>\n<li><strong>Limit scope and claims:<\/strong> Request only what you need and apply least privilege on APIs.<\/li>\n<\/ul>\n<h2 id=\"implementation-tips\">Implementation Tips and Tooling<\/h2>\n<p>You don\u2019t have to build SSO from scratch. Solid libraries and cloud IdPs make it faster and safer.<\/p>\n<h3>Choosing the right protocol<\/h3>\n<ul>\n<li><strong>Legacy enterprise apps:<\/strong> SAML is often expected by corporate IdPs and portals.<\/li>\n<li><strong>Modern web\/mobile:<\/strong> OIDC with Authorization Code + PKCE is typically best.<\/li>\n<\/ul>\n<h3>Libraries and frameworks<\/h3>\n<ul>\n<li><strong>OIDC:<\/strong> Use well-vetted client libraries that handle discovery, PKCE, token validation, and refresh.<\/li>\n<li><strong>SAML:<\/strong> Choose mature toolkits that manage XML signatures, encryption, and metadata.<\/li>\n<\/ul>\n<h3>Metadata, discovery, and configuration<\/h3>\n<ul>\n<li><strong>SAML metadata:<\/strong> Exchange IdP and SP metadata (endpoints, certs). Automate updates where possible.<\/li>\n<li><strong>OIDC discovery:<\/strong> Use the .well-known discovery document to find authorization, token, JWKS, and logout endpoints.<\/li>\n<li><strong>Redirect URIs:<\/strong> Register exact redirect\/callback URIs and avoid wildcards. Mismatches cause login failures.<\/li>\n<\/ul>\n<h3>Attributes and claims mapping<\/h3>\n<ul>\n<li>Define which attributes\/claims your app needs (email, groups, roles).<\/li>\n<li>Normalize names between IdP and app. For SAML, align NameID format; for OIDC, map claim names and types.<\/li>\n<li>Keep authorization separate: use groups\/roles but validate them server-side.<\/li>\n<\/ul>\n<h3>Test and observe<\/h3>\n<ul>\n<li><strong>Test IdPs and tenants:<\/strong> Use staging tenants and sample IdPs to validate flows.<\/li>\n<li><strong>Introspect and logs:<\/strong> Enable verbose logging in lower environments, including assertion\/token validation details.<\/li>\n<li><strong>Monitor health:<\/strong> Track login success rates, token errors, and clock drift indicators.<\/li>\n<\/ul>\n<h2 id=\"common-pitfalls\">Common Pitfalls and Troubleshooting<\/h2>\n<ul>\n<li><strong>Clock drift:<\/strong> Even small time differences can break token\/condition checks. Sync NTP across systems.<\/li>\n<li><strong>Incorrect redirect\/ACS URLs:<\/strong> Typos or environment mismatches prevent successful handoffs.<\/li>\n<li><strong>Skipping validation:<\/strong> Failing to verify signatures, issuer, or audience invites impersonation risk.<\/li>\n<li><strong>Leaking tokens to the browser address bar:<\/strong> Avoid implicit\/fragment flows; use Authorization Code + PKCE instead.<\/li>\n<li><strong>Third-party cookie issues:<\/strong> Browser restrictions can affect cross-site SSO if your setup relies on third-party cookies; prefer same-site sessions and standards-compliant flows.<\/li>\n<li><strong>NameID\/attribute mismatches (SAML):<\/strong> If your app expects email but the IdP sends a different attribute, users can\u2019t log in. Agree on a schema early.<\/li>\n<li><strong>JWKS caching gotchas (OIDC):<\/strong> Handle key rotation; don\u2019t pin to a single key forever.<\/li>\n<li><strong>Iframe-based login:<\/strong> Many IdPs block framing for security. Use top-level redirects or system browsers for mobile.<\/li>\n<li><strong>Overbroad scopes and long-lived refresh tokens:<\/strong> Request only what\u2019s needed; rotate and revoke on suspicion.<\/li>\n<\/ul>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>SSO delivers a smoother experience and stronger security by centralizing authentication. SAML and OIDC both get you there, but they fit different contexts. SAML is a reliable choice for enterprise web SSO, while OIDC with Authorization Code + PKCE is ideal for modern web and mobile apps.<\/p>\n<p>Whichever you choose, follow the fundamentals: validate assertions and tokens, use HTTPS, configure redirects precisely, and observe your system in production. Do this well and you\u2019ll give users fast, safe access across your application ecosystem.<\/p>\n<h2 id=\"frequently-asked-questions\">Frequently Asked Questions<\/h2>\n<p><strong>Is SAML more secure than OIDC?<\/strong><\/p>\n<p>Both can be highly secure when implemented correctly. OIDC benefits from modern JWT tooling and the Authorization Code + PKCE flow, while SAML relies on robust XML signatures and strict validation. Security depends more on correct configuration than the protocol itself.<\/p>\n<p><strong>Which should I use for a new web or mobile app?<\/strong><\/p>\n<p>Use OIDC with Authorization Code + PKCE. It\u2019s designed for modern apps, has excellent library support, and fits SPAs and native apps well. Choose SAML primarily when integrating with enterprise IdPs that require it.<\/p>\n<p><strong>Do I need both SAML and OIDC?<\/strong><\/p>\n<p>Some platforms support both to serve different customers. If your customers\u2019 identity systems vary, offering both can reduce friction. Internally, standardize on one to simplify operations if possible.<\/p>\n<p><strong>How do I log users out across all apps?<\/strong><\/p>\n<p>Use protocol-specific logout (SAML SLO or OIDC front-\/back-channel logout) and align session lifetimes. In practice, full cross-app logout can be complex; combine centralized logout with short sessions and token revocation.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how SSO works with clear, step-by-step SAML and OIDC walkthroughs. Understand tokens, redirects, security tips, and best practices for modern apps.<\/p>\n","protected":false},"author":1,"featured_media":608,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[8],"tags":[],"class_list":["post-609","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-posts"],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/i0.wp.com\/blog.asambe.ai\/wp-content\/uploads\/2026\/02\/2026-02-16-19-48-22-data.png?fit=1024%2C1024&ssl=1","_links":{"self":[{"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/posts\/609","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/comments?post=609"}],"version-history":[{"count":1,"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/posts\/609\/revisions"}],"predecessor-version":[{"id":610,"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/posts\/609\/revisions\/610"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/media\/608"}],"wp:attachment":[{"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/media?parent=609"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/categories?post=609"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.asambe.ai\/index.php\/wp-json\/wp\/v2\/tags?post=609"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}