SAML vs OIDC: Understanding How Modern Authentication Works

If you’ve worked with Single Sign-On (SSO), you’ve probably come across two names repeatedly: SAML and OIDC.

Both are widely used for authentication, both allow applications to delegate authentication to an Identity Provider (IdP), and both can provide users with a seamless SSO experience.

But they work quite differently.

SAML is heavily used in enterprise applications and has been around for years. OIDC, built on top of OAuth 2.0, is widely used in modern web applications, mobile applications, and API-driven architectures.

So what actually happens when a user logs in using SAML?

What changes when the same application uses OIDC?

And why would an organization choose one over the other?

Let’s break it down from a developer’s perspective.

1. SAML

SAML, or Security Assertion Markup Language, is an XML-based standard commonly used for exchanging authentication and identity information between an Identity Provider and an application.

A typical SAML setup has two important components:

  • Identity Provider (IdP) — authenticates the user.
  • Service Provider (SP) — the application the user wants to access.

For example, imagine an employee wants to access an internal HR application.

Instead of the HR application managing the employee’s password, the application can redirect the user to the organization’s Identity Provider.

The IdP authenticates the user and sends a SAML response back to the application.

The application validates that response and creates a session for the user.

The important idea is:

The application doesn’t need to directly authenticate the user’s credentials. The Identity Provider does that.

SAML Assertion

One of the most important concepts in SAML is the SAML Assertion.

The assertion contains information about the authenticated user.

A simplified example might look like:

<saml:Assertion>
<saml:Issuer>
https://identity.example.com
</saml:Issuer>
<saml:Subject>
user@example.com
</saml:Subject>
<saml:AttributeStatement>
<saml:Attribute Name="email">
user@example.com
</saml:Attribute>
<saml:Attribute Name="firstName">
John
</saml:Attribute>
<saml:Attribute Name="lastName">
Doe
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>

This isn’t a complete production SAML assertion, but it illustrates the basic idea.

The application can use these attributes to identify the user and populate the user’s profile.

How a SAML Login Works

Let’s look at the typical SP-initiated SSO flow.

User
│
│ 1. Access application
▼
Service Provider
│
│ 2. SAML Authentication Request
▼
Identity Provider
│
│ 3. Authenticate user
│
│ 4. SAML Response
▼
Service Provider
│
│ 5. Validate Assertion
▼
Authenticated User

Let’s walk through it.

Step 1 — User accesses the application

The user opens:

https://app.example.com

The application determines that the user isn’t authenticated.

Step 2 — Application sends a SAML Authentication Request

The application redirects the user’s browser to the Identity Provider.

The request contains information identifying the application and the requested authentication context.

Step 3 — Identity Provider authenticates the user

The IdP may ask the user for credentials, MFA, or another authentication method.

If the user already has an active IdP session, they may not need to enter credentials again.

This is one of the main benefits of SSO.

Step 4 — IdP sends a SAML Response

After authentication, the IdP generates a SAML Response containing the assertion.

The browser carries that response back to the application.

Step 5 — Application validates the assertion

The application should validate important properties such as:

  • Signature
  • Issuer
  • Audience
  • Expiration
  • Recipient
  • Destination
  • Subject
  • Conditions

Only after successful validation should the application establish an authenticated session.

2. OIDC

Now let’s look at OpenID Connect, commonly called OIDC.

OIDC is an authentication protocol built on top of OAuth 2.0.

This distinction is important.

OAuth 2.0 itself is primarily an authorization framework.

OIDC adds an identity layer on top of OAuth 2.0 so applications can authenticate users.

In simple terms:

OAuth 2.0
│
│ Authorization
▼
Access to resources
OIDC
│
├── OAuth 2.0
│
└── Identity layer
│
▼
User authentication

OIDC is commonly used by modern identity platforms and providers.

The Important OIDC Tokens

OIDC introduces several important tokens.

ID Token

The ID Token contains information about the authenticated user.

It is usually a JWT.

A simplified payload might look like:

{
"iss": "https://identity.example.com",
"sub": "123456789",
"aud": "my-application",
"email": "user@example.com",
"name": "John Doe",
"iat": 1780000000,
"exp": 1780003600
}

Some important claims include:

iss

The issuer of the token.

https://identity.example.com

sub

The unique identifier of the user within the issuer’s namespace.

aud

The intended audience, typically your application.

iat

Issued-at timestamp.

exp

Expiration timestamp.

The ID Token is primarily about who the user is.

Access Token

The Access Token is used to access protected resources.

For example:

Application
│
│ Access Token
▼
API

The API validates the access token and determines whether the token provides the required permissions.

This leads to one of the most common mistakes developers make:

An ID Token and an Access Token are not interchangeable.

An ID Token tells the application about the authenticated user.

An Access Token is intended to authorize access to protected resources.

Refresh Token

A Refresh Token can be used to obtain new access tokens without requiring the user to authenticate again, depending on the application’s architecture and the authorization server’s configuration.

Conceptually:

Refresh Token
│
▼
Identity Provider
│
▼
New Access Token

Whether and how refresh tokens are issued depends on the client type, provider, scopes, policies, and security configuration.

OIDC Authentication Flow

For modern applications, the Authorization Code Flow with PKCE is an important OIDC flow.

The high-level flow looks like this:

User
│
│ 1. Login
▼
Application
│
│ 2. Authorization Request
▼
Identity Provider
│
│ 3. Authenticate User
│
│ 4. Authorization Code
▼
Application
│
│ 5. Token Request
▼
Identity Provider
│
│ 6. ID Token + Access Token
▼
Application
│
▼
Authenticated User

Let’s break it down.

Step 1 — User accesses the application

The user opens the application.

The application determines that the user doesn’t have an authenticated session.

Step 2 — Application redirects to the IdP

The application sends the user to the Identity Provider’s authorization endpoint.

A simplified request might contain:

client_id
redirect_uri
response_type=code
scope=openid profile email
state
nonce
code_challenge

For example:

https://identity.example.com/authorize
?client_id=my-app
&response_type=code
&scope=openid%20profile%20email
&redirect_uri=https://app.example.com/callback
&state=abc123
&nonce=xyz456
&code_challenge=...

Step 3 — User authenticates

The Identity Provider handles authentication.

This could involve:

  • Username and password
  • MFA
  • Social login
  • Enterprise SSO
  • Passwordless authentication
  • Biometrics
  • Other authentication mechanisms

The application doesn’t necessarily need to know which authentication method was used.

Step 4 — Identity Provider returns an Authorization Code

After successful authentication, the IdP redirects the browser back to the application’s callback URL.

Instead of immediately returning tokens through the browser, the IdP returns an authorization code.

For example:

https://app.example.com/callback
?code=abc123
&state=xyz456

Step 5 — Application exchanges the code for tokens

The application sends the authorization code to the IdP’s token endpoint.

The IdP validates the request and returns tokens.

For example:

{
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}

Depending on the configuration, a refresh token may also be returned.

Step 6 — Application validates the ID Token

The application validates the ID Token before treating the user as authenticated.

Important checks include:

  • Signature
  • Issuer
  • Audience
  • Expiration
  • Nonce
  • Token type and relevant claims

After successful validation, the application can establish its own session.

3. SAML vs OIDC

Now we can compare the two protocols directly.

Press enter or click to view image in full size

This doesn’t mean SAML is only for old applications or that OIDC should always replace it.

Both continue to have legitimate use cases.

4. Authentication Flow: SAML vs OIDC

The biggest difference becomes easier to understand when we visualize the flows.

SAML

┌──────┐
│ User │
└───┬──┘
│
│ Access Application
▼
┌─────────────┐
│ SP │
│ Application │
└──────┬──────┘
│
│ SAML Request
▼
┌─────────────┐
│ IdP │
└──────┬──────┘
│
│ Authentication
▼
┌─────────────┐
│ IdP │
└──────┬──────┘
│
│ SAML Response
▼
┌─────────────┐
│ SP │
└──────┬──────┘
│
│ Validate Assertion
▼
Authenticated
User

The key object being exchanged is the SAML Response containing the assertion.

OIDC

┌──────┐
│ User │
└───┬──┘
│
│ Login
▼
┌─────────────┐
│ Application │
└──────┬──────┘
│
│ Authorization Request
▼
┌─────────────┐
│ IdP │
└──────┬──────┘
│
│ Authenticate
│
│ Authorization Code
▼
┌─────────────┐
│ Application │
└──────┬──────┘
│
│ Code Exchange
▼
┌─────────────┐
│ IdP │
└──────┬──────┘
│
│ ID Token + Access Token
▼
┌─────────────┐
│ Application │
└─────────────┘

The key difference is that OIDC commonly uses an authorization code followed by a token exchange.

5. Understanding the Security Differences

Authentication protocols are not just about moving user information around.

The application needs to prove that the information came from a trusted source and that it was intended for the application.

Issuer Validation

The application should verify who issued the token or assertion.

For example:

iss = https://identity.example.com

If the application expects tokens from a particular issuer, a token from an unexpected issuer should not automatically be trusted.

Audience Validation

The application should verify that the token or assertion was intended for it.

For example:

aud = my-application

A valid token issued for another application should not automatically be accepted by your application.

Expiration

Tokens and assertions should have an expiration time.

For example:

exp = 1780003600

The application should reject expired credentials.

Signature Validation

SAML assertions and OIDC tokens can be digitally signed.

The application validates the signature using trusted cryptographic keys.

This helps establish that the identity information hasn’t been modified and originated from the expected issuer.

OIDC: State and Nonce

Two important OIDC security parameters are state and nonce.

State

state helps protect the authorization flow against attacks such as cross-site request forgery.

The application generates a value before starting authentication.

For example:

state = random-value-123

The value is associated with the authentication request.

When the IdP redirects the user back, the application verifies that the returned state matches the expected value.

Nonce

nonce helps protect against replay and token substitution scenarios.

The application generates a nonce during the authentication request.

The nonce is later validated against the corresponding value in the ID Token.

PKCE

Proof Key for Code Exchange, commonly called PKCE, adds another security layer to the authorization code flow.

The application generates a secret value called the code_verifier.

It derives a code_challenge from that value and sends the challenge during the authorization request.

Later, during the token exchange, the application sends the original verifier.

Conceptually:

Application
Generate:
code_verifier
│
▼
Generate:
code_challenge
│
▼
Authorization Request
│
▼
IdP
│
▼
Authorization Code
│
▼
Token Request
+
code_verifier
│
▼
IdP
│
▼
Tokens

The authorization server can verify that the party exchanging the authorization code possesses the original verifier.

6. When Would You Use SAML?

SAML continues to be heavily used in enterprise environments.

For example, imagine a company has an existing identity platform that supports SAML integrations.

They want employees to access your SaaS application using their existing corporate accounts.

Your application can act as the Service Provider, while the customer’s identity system acts as the Identity Provider.

Employee
│
▼
Your SaaS Application
│
│ SAML
▼
Customer's Identity Provider

SAML can therefore be particularly relevant when:

  • Enterprise customers require SAML
  • Customers already have established SAML infrastructure
  • You’re integrating with existing enterprise identity platforms
  • The application needs enterprise SSO

Supporting SAML can also be an important requirement for B2B SaaS products because enterprise customers may have established identity and security requirements.

7. When Would You Use OIDC?

OIDC fits naturally into modern application architectures.

For example:

Web Application
│
▼
OIDC
│
▼
Identity Provider

OIDC is particularly useful for:

  • Modern web applications
  • Single-page applications
  • Mobile applications
  • API-driven applications
  • Microservices
  • Cloud-native applications
  • Modern identity platforms

It also works naturally with OAuth 2.0-based authorization for APIs.

For example:

User
│
▼
Web Application
│
│ OIDC
▼
Identity Provider
│
│ Access Token
▼
API

This separation between authentication and API authorization is one reason OIDC/OAuth-based architectures are common in modern applications.

8. Can an Application Support Both?

Yes.

In fact, an application can support both SAML and OIDC.

Consider a SaaS application with two types of customers.

Some customers may already have enterprise SAML infrastructure.

Other customers may use modern OIDC-based authentication.

The architecture could look like this:

                    ┌──────────────────┐
│ │
│ Application │
│ │
└────────┬─────────┘
│
┌────────────┴────────────┐
│ │
OIDC SAML
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Modern IdP │ │ Enterprise │
│ │ │ IdP │
└──────────────┘ └──────────────┘

The application doesn’t necessarily need to force every customer into the same federation protocol.

Instead, it can support different identity connections depending on the customer’s requirements.

This is particularly useful in B2B SaaS applications.

9. Migrating from SAML to OIDC

Migrating from SAML to OIDC isn’t simply a matter of changing XML to JSON.

There are several architectural differences.

SAML

SAML Assertion
│
▼
User Attributes
│
▼
Application Session

OIDC

Authorization Code
│
▼
Token Exchange
│
▼
ID Token / Access Token
│
▼
Application Session / API Access

During a migration, developers need to consider:

User identity mapping

A SAML system might identify a user using an email address or another attribute.

OIDC commonly uses the sub claim as a stable identifier within the issuer context.

Therefore, you need a deliberate user-mapping strategy.

Attribute mapping

SAML attributes may look like:

email
firstName
lastName
department
role

OIDC may expose similar information as claims:

{
"email": "user@example.com",
"given_name": "John",
"family_name": "Doe"
}

The names and semantics aren’t necessarily identical.

Session handling

The application may have been designed around SAML sessions and browser redirects.

An OIDC implementation may introduce:

  • Authorization codes
  • Token expiration
  • Refresh tokens
  • Access token validation
  • PKCE
  • Different logout behavior

These need to be considered as part of the migration.

Supporting both during migration

A gradual migration can sometimes support both protocols temporarily:

                Application
│
┌──────────┴──────────┐
│ │
SAML OIDC
│ │
Existing Users New Users

This allows organizations to transition identity infrastructure without requiring every integration to change simultaneously.

The exact migration strategy depends on the existing identity architecture and whether the application or the Identity Provider is being replaced.

10. Common Developer Mistakes

There are several mistakes developers commonly make when implementing SAML or OIDC.

Mistake 1: Treating ID Tokens as API tokens

An ID Token is intended to communicate identity information to the client application.

It should not automatically be treated as an API authorization credential.

For APIs, use the appropriate Access Token and validate it according to the API’s authorization requirements.

Mistake 2: Not validating the issuer

A token being correctly signed doesn’t automatically mean your application should trust it.

The application should verify that it was issued by the expected issuer.

Mistake 3: Not validating the audience

A valid token intended for another application should not automatically be accepted.

Always validate the intended audience where applicable.

Mistake 4: Skipping PKCE

For authorization code flows where PKCE is applicable, don’t treat it as an optional implementation detail.

PKCE helps protect the authorization code exchange.

Mistake 5: Ignoring state

The application should generate and validate state during the authorization flow.

It is an important protection for browser-based authentication flows.

Mistake 6: Ignoring nonce

When using OIDC authentication, the application should properly generate and validate nonce where required by the flow.

Mistake 7: Assuming SAML and OIDC are interchangeable

They solve related problems, but their protocols, messages, artifacts, and implementation models are different.

A migration therefore requires more than changing the authentication endpoint.

11. The Bigger Picture

SAML and OIDC are often presented as competitors.

In practice, it’s more useful to think of them as two different protocols that can coexist.

A modern identity architecture might look like:

                         Identity Layer
│
┌────────────────┴────────────────┐
│ │
OIDC SAML
│ │
▼ ▼
Modern Applications Enterprise Customers
│ │
└────────────────┬────────────────┘
│
▼
Application

An organization might use OIDC for its modern applications while continuing to support SAML for enterprise integrations.

The protocols don’t necessarily have to compete.

Final Thoughts

SAML and OIDC both play important roles in the identity ecosystem, but they approach authentication differently.

SAML is an XML-based federation protocol that has become deeply established in enterprise SSO.

OIDC adds an identity layer to OAuth 2.0 and fits naturally into modern web, mobile, and API-driven architectures.

The important concepts to remember are:

SAML
→ SAML Request
→ SAML Response
→ SAML Assertion
→ XML
→ Enterprise SSO
OIDC
→ Authorization Request
→ Authorization Code
→ Token Exchange
→ ID Token
→ Access Token
→ JSON/JWT
→ Modern application authentication

Neither protocol should be viewed simply as a replacement for the other.

The right architecture depends on the application’s requirements, the identity providers it needs to integrate with, the client types involved, and the existing identity infrastructure.

For developers working on SSO systems, understanding both is increasingly valuable — especially when building applications that need to support multiple identity providers and authentication models.

In this article:
Share on social media: