Chapter 11
SAML
Similar to OAuth and OIDC, SAML (Security Assertion Markup Language) is another essential protocol used in the IAM world. Even though it was originally developed in 2006 and people say that OAuth/OIDC is replacing SAML, the reality is that SAML is still widely and actively being used and deployed in the industry today. The reason is that there are some features that SAML has but OAuth/OIDC doesn't. Hence, having a good understanding is crucial for any IAM professionals.
The most widely used version is SAML 2.0, which was developed to fix some security issues in SAML 1.0, and when people talk about SAML, it is usually SAML 2.0 they are referring to. We will follow that fashion in this post.
Key Points
- SAML Overview:
- XML-based standard for exchanging authentication and authorization data.
- Used for SSO, cross-domain SSO, and identity federation.
- SSO vs. Cross-Domain SSO vs. Identity Federation:
- SSO: Single sign-on within the same domain.
- Cross-Domain SSO: SSO across different domains (often different organizations).
- Identity Federation: Enables users to access resources across different domains using the same digital identity.
- IDP (Identity Provider) and SP (Service Provider):
- IDP: Authenticates users and issues assertions.
- SP: Provides services and relies on IDP for authentication.
- SAML Flows:
- SP-Initiated Flow: User tries to access SP, SP redirects to IDP for authentication, IDP responds to SP with assertion.
- IDP-Initiated Flow: User authenticates at IDP, IDP forwards assertion to SP.
- SAML Setup:
- Circle of Trust (COT): Establishes trust between IDP and SP.
- SAML Metadata: XML document containing information about SAML entities (IDP, SP).
- Includes entityID, SSO descriptor (endpoints, certificates, keys, etc.).
- Metadata Exchange: IDP and SP exchange metadata to establish trust.
- SAML Messages and Bindings:
- SAML Messages: XML-based messages (e.g., AuthnRequest, Response) exchanged between IDP and SP.
- SAML Bindings: Define how messages are transported (HTTP POST, HTTP Redirect, HTTP Artifact, SOAP).
- SAML Request:
- Sent from SP to IDP to initiate authentication.
- Contains information like IssueInstant, Destination, ProtocolBinding, AssertionConsumerServiceURL, Issuer, NameIDPolicy, RequestedAuthnContext.
- SAML Response and Assertion:
- SAML Response: Sent from IDP to SP after authentication.
- Contains a SAML Assertion with user identity information (e.g., Subject, Issuer, Conditions, Audience, AuthnContext, Attributes).
SAML Overview
SAML was published by the open standard consortium OASIS (Organization for the Advancement of Structured Information Standards) in 2006 to address the issue of repeated password inputs and SSO (Single Sign-On) was introduced during that time.
At that time, JSON or YAML was not quite adopted yet and XML was popular, so SAML was developed based on XML.
The major use case scenarios for SAML are: SSO/Cross-Domain SSO and Identity Federation. Let's understand them first before diving into SAML.
SSO vs. Cross-Domain SSO vs. Identity Federation
When talking about SAML, sometimes you will encounter the so-called 'Cross-Domain SSO' and 'Identity Federation'. It's good to know a little bit about SSO, Cross-Domain SSO and Identity Federation.
SSO
SSO could be referring to just the general concept of single sign-on, that is when you have multiple applications and once you sign into one application, you don't have to sign into other applications. These applications could be within the same domain or from different domains. However, when SSO is used against Cross-Domain SSO, the former usually means SSO within the same domain.
The implementation for same-domain SSO is like a typical setup where you have a centralized IAM platform and other applications will redirect users to this centralized IAM platform for authentication. This redirect mechanism could be based on standard protocol like SAML or OIDC. It could also be something custom developed. The goal is to have all apps integrated with the centralized IAM platform so that SSO can be done with those Apps.
Cross-Domain SSO
Cross-Domain SSO, like its name, is for SSO from different domains. When applications are from different domains, they could be from different departments within an organization, but more often than not, they are applications from other organizations.
So here we are talking about SSO across different companies or organizations, whose infrastructure environment could be very different from same-domain SSO. Custom development is usually limited, as one company won't easily allow another company to access their APIs or other resources. In this case, it's better to use standard protocols like SAML or OIDC. For enterprise-to-enterprise SSO integration, SAML is sometimes preferred over OIDC.
Identity Federation
Identity Federation (or Federated Identity) is a system which allows identities from different enterprises (domains) to use the same digital identity to access all applications and networks.
In a general sense, SSO is needed to fulfill Identity Federation, and since Identity Federate usually deals with different organizations/enterprises, it is closer to the concept of Cross-Domain SSO.
When identities are federated across multiple organizations, their profile information is shared to those organizations as well so that the organizations can operate more efficiently using that set of identity profiles. In order for that to happen, besides the trusted relationship established for Cross-Domain SSO, organizations need to have an agreement on what profile information to be shared as well. After that, protocols like SAML or OIDC can be leveraged again to implement it.
IDP (Identity Provider) and SP (Service Provider)
Now, let's jump on the boat of SAML. There are two major parties in SAML: IDP and SP, they are both called SAML entities.
IDP (Identity Provider) is the party responsible for Authenticating the user while SP (Service Provider) is the party responsible for providing services, who will NOT authenticate the user but delegate authentication to IDP.

SP-Initiated Flow
The reason for delegating authentication to IDP is that in this case IDP can act as a centralized platform to authenticate users, that is when there are multiple SPs, they can all rely on IDP for authentication. This will help to fulfill SSO, because once a user login to IDP, IDP will maintain an active user session (e.g. browser cookie) and next time when the same user is redirected to IDP from another SP, he doesn't need to login anymore.
IDP is usually connected to a centralized User Directory where all user profile information for authentication are present.
SP-Initiated Flow and IDP-Initiated Flow
Once we understand what IDP and SP are, we can look at the workflows in SAML. There are two workflows in SAML: SP-Initiated flow and IDP-Initiated flow.
SP-Initiated flow is more frequently seen and the high level process is the same as shown in the above diagram. A user first tries to access some services provided by SP. In order to provide the service, SP needs to authenticate the user to know who he is and what profile information he possesses. Furthermore, to follow the pattern of SSO, SP redirects the user to IDP for authentication. If the user hasn't authenticated in IDP before or the authenticated session has expired, the user will be presented with a login page.
Once a user has finished authentication, IDP will pull the user profile information from the centralized user directory and generate a response to send back to SP. SP then parses and verifies the response to extract user information. Also, since the user is verified, a lot of times, SP will create a user session as well so that next time when the user comes, he doesn't need to be redirected to IDP again. Note this SP user session is specifically for this SP and will store locally on the SP side and it is different from the IDP user session.
IDP-Initiated flow is similar to SP-Initiated flow. The difference is that instead of SP redirecting users to IDP for authentication, the user directly accesses IDP and authenticates at the IDP side. Then IDP forwards the authentication result to SP.
One thing to note is that as IDP is usually integrated with multiple SP, it needs to know which SP to forward the authentication result. This is usually indicated when the user accesses IDP in the first step.

IDP-Initiated Flow
SAML Setup
Now that we have some general understanding of SAML, we can check on how SAML is set up. This setup is needed before the SAML flow can work.
COT (Circle of Trust)
Before SP can delegate authentication to IDP or use the authentication result from IDP, a trusted relationship needs to be established between IDP and SP. This is kind of intuitive, as a SP just can't delegate authentication to some random party or use the authentication result from it. Vice versa, IDP can't just forward authentication results to some random SP to disclose the user information. Some form of trusted-relationship needs to be established.

Circle of Trust
Before we look at how the trust is established, let's take a look at the 'end state'. Eventually at some point, multiple applications (SP) need to establish a trusted relationship with at least one IDP (could be more which is referred to as muti-IDP). As illustrated in the above diagram, all SPs and IDPs are in the same league (circle). This basically means, any SP can delegate authentication to an IDP in the circle and any authentication result sent by IDP is trusted by SP (though more validation is needed to make sure no tampering on the response which we will explore later).
The circle of trust (COT) is the prerequisite for either IDP-Initiated or SP-Initiated SAML flow, and a lot of times, a COT already exists and we just need to add the new SP to the COT.
SAML Metadata
Now that we know COT is needed before SAML flow, the question comes as how to establish this handshake. The answer is through a method called Metadata Exchange. Let's first understand what SAML Metadata is.
In theory, SAML metadata is an XML-based configuration data file which includes various information about the SAML entity (IDP or SP) such as identifier, binding endpoints, certificates, keys, etc. Since IDP and SP are serving different purposes in a SAML flow, it's straightforward to tell that IDP and SP will contain different information. On the other hand, they share some similar format and content as well.
Here is an example of IDP and SP metadata combined. We can see the combined version of IDP and SP metadata from time to time. This is because an IDP platform can also serve as a SP. However, SP doesn't usually serve as an IDP. We show a combined version here for conciseness.

General Format
The general format of metadata for IDP looks like:
- EntityDescriptor
- IDPSSODescriptor
- Extensions (optional, IdP discovery and algorithm support, not much used today)
- KeyDescriptor (optional, but usually included)
- ArtifactResolutionService (optional, legacy and not much used today)
- SingleLogoutService (optional)
- NameIDFormat (optional)
- SingleSignOnService (required at least one)
- Organization (Not Important)
- ContactPerson (Not Important)
- IDPSSODescriptor
The general format of metadata for SP looks like:
- EntityDescriptor
- SPSSODescriptor
- Extensions (optional, service discovery, algorithm support and entity category, not much used today)
- KeyDescriptor (optional, but usually included)
- SingleLogoutService (optional)
- NameIDFormat (optional)
- AssertionConsumerService (required at least one)
- Organization (Not Important)
- ContactPerson (Not Important)
- SPSSODescriptor
The most important part for both IDP and SP metadata are the entityID and SSO Descriptor. Organization and ContactPerson are more of reference information types which are usually ignored during SAML integration.
Unique Identifier of SAML Entity
Each SAML Entity (SP and IdP) that participates in SAML protocol should have a Unique Identifier. This identifier could be a URI with a maximum 1024 characters. In the above example, the IDP Unique Identifier (entityID) is "https://idp.example.org/idp.xml", while the SP Unique Identifier (entityID) is "https://sp.example.org/sp.xml". They are both within the <EntityDescriptor>, which is the root element of either IDP metadata or SP metadata.
It might look weird to use a URL as an identifier at first. But seeing that each application usually has a unique home URL and that URL represents the application well, it kind of makes sense to use URL as the entity identifier. Actually, that's what you see most of the time you see in practice.
SSO Descriptor
SSO Descriptor contains Extensions, KeyDescriptor, ArtifactResolutionService (IDP), SingleLogoutService, NameIDFormat, SingleSignOnService(IDP), AssertionConsumerService(SP).
Extensions
The extensions part can contain IDP Discovery, Algorithm Support etc. This is not much used today and is usually omitted.
Key Descriptor
This part of metadata includes information of one or more public keys used in the SAML flow. The SAML request/response can be signed as well as encrypted. In order to verify the signature or decrypt the request/response, a public key is needed. Usually the public key to verify that information is provided inline along with the request/response. However, pre-registered keys as provided in metadata can prevent invalid public keys from being presented in the SAML request/response.
ArtifactResolutionService (ARS)
This is the IDP endpoint for resolving the artifact when Http Artifact Binding is used in the SAML flow. Binding method basically means how IDP sends the authenticated user information back to SP.
There are two ways of binding in SAML: Http Front-Channel (Redirect or Post) and Http Back-Channel (Artifact Binding). The most frequently used is the Http Front-Channel with Post method. We will look more into this later.
SingleLogoutService
This endpoint is for Single Logout Service. When Single Logout Service is implemented, both IDP and SP should present a SingleLogoutService endpoint. When a single logout action is triggered from the IDP SingleLogoutService endpoint, the IDP logs the user off and it also sends multiple requests to all other SP SingleLogoutService endpoints to log the user off on the SP side. Note not all SAML implementations support Single Logout.
NameIDFormat
The NameIDFormat is used to define the NameID value in the IDP response to SP. IDP presents a list of NameIDFormats in its metadata to show what kind of NameIDFormats it supports in the IDP Response. SP presents a list of NameIDFormats to show what kind of NameIDFormats it can request and parse in the IDP response.
A list of examples here:
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified: Indicates that the format of the NameID is not specified.
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress: Indicates that the NameID is an email address.
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName: Indicates that the NameID is an X.509 distinguished name.
- urn:oasis:names:tc:SAML:1.1:nameid-format:kerberos: Indicates that the NameID is a Kerberos principal name.
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent: Indicates that the NameID is a persistent identifier that is unique within the scope of the IDP.
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient: Indicates that the NameID is a transient identifier that is unique within the scope of the IDP and is not intended to be persisted.
SingleSignOnService
This is IDP's endpoint, which is used as the entry URL to start the SSO service. For example, in the SP-Initiated flow, SP will send requests to this endpoint to start the flow. At least one value is required in the IDP metadata.
AssertionConsumerService (ACS)
This is SP's endpoint. It is used by IDP when forwarding its SAML response to the SP, where SP will consume the response. At least one value is required from SP metadata.
Exchange of Metadata
As seen from the previous post, IDP metadata and SP metadata are XML-based data containing important information for the SAML entity (IDP and SP).
IDP metadata should be loaded into SP so that IDP can be recognized by SP. Vice versa, SP metadata should be loaded into IDP so that SP can be recognized by IDP.

Metadata Exchange
In reality, there is no specific standard way required to load those information into each party. We can send the metadata to each party as an email attachment, or publish it online and let the other party retrieve it via URL. Once the metadata information is received, it needs to be updated in the IDP/SP system.
A lot of times, an IDP is a well developed IAM platform, an engineer can directly import the SP metadata file into it. On the other hand, SP could be an in-house developed application, and there is usually no straight-forward import function. In this case, a developer will extract the key values from IDP metadata and manually input into SP side.
All in all, the key information from IDP metadata needs to be configured in SP, and the key information from SP metadata needs to be configured in IDP.
How SAML Works
Now that we have established the trust relationship between IDP and SP, we can start to look at how SAML flow really works under the hood.
SAML Messages
SAML Messages in SAML are XML-based to convey SAML information between IDP and SP. For example, in the SP-initiated flow, SP will first send a SAML Request message to IDP and later IDP will send a SAML Response message back to SP. During the transport time, the XML-based content will be encoded using Base64.
Here is an example of an encoded sample SAML request:
PHNhbWxwOkF1dGhuUmVxdWVzdCB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiB4bWxuczpzYW1sPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iT05FTE9HSU5fODA5NzA3ZjAwMzBhNWQwMDYyMGM5ZDlkZjk3ZjYyN2FmZTlkY2MyNCIgVmVyc2lvbj0iMi4wIiBQcm92aWRlck5hbWU9IlNQIHRlc3QiIElzc3VlSW5zdGFudD0iMjAxNC0wNy0xNlQyMzo1Mjo0NVoiIERlc3RpbmF0aW9uPSJodHRwOi8vaWRwLmV4YW1wbGUuY29tL1NTT1NlcnZpY2UucGhwIiBQcm90b2NvbEJpbmRpbmc9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpiaW5kaW5nczpIVFRQLVBPU1QiIEFzc2VydGlvbkNvbnN1bWVyU2VydmljZVVSTD0iaHR0cDovL3NwLmV4YW1wbGUuY29tL2RlbW8xL2luZGV4LnBocD9hY3MiPg0KICA8c2FtbDpJc3N1ZXI+aHR0cDovL3NwLmV4YW1wbGUuY29tL2RlbW8xL21ldGFkYXRhLnBocDwvc2FtbDpJc3N1ZXI+DQogIDxzYW1scDpOYW1lSURQb2xpY3kgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjE6bmFtZWlkLWZvcm1hdDplbWFpbEFkZHJlc3MiIEFsbG93Q3JlYXRlPSJ0cnVlIi8+DQogIDxzYW1scDpSZXF1ZXN0ZWRBdXRobkNvbnRleHQgQ29tcGFyaXNvbj0iZXhhY3QiPg0KICAgIDxzYW1sOkF1dGhuQ29udGV4dENsYXNzUmVmPnVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphYzpjbGFzc2VzOlBhc3N3b3JkUHJvdGVjdGVkVHJhbnNwb3J0PC9zYW1sOkF1dGhuQ29udGV4dENsYXNzUmVmPg0KICA8L3NhbWxwOlJlcXVlc3RlZEF1dGhuQ29udGV4dD4NCjwvc2FtbHA6QXV0aG5SZXF1ZXN0Pg==The decoded XML content is

SAML Bindings
In SAML, bindings are methods used to transport SAML messages between IDP and SP. There are several bindings defined in the SAML specification:
- HTTP POST Binding
- HTTP Redirect Binding
- HTTP Artifact Binding
- SOAP Binding
HTTP POST Binding
This is the most frequently used binding method. The SAML messages are transported via HTTP POST requests, where the message content is in the payload of an HTML form.
HTTP Redirect Binding
This method is sometimes used as well. The SAML messages are transported via HTTP GET requests. The message is transported as a URL query string parameter called "SAMLRequest".
HTTP Artifact Binding
This binding is less used today. It doesn't send the full SAML message in the HTTP call, but instead, using an intermediary token as an artifact. And then, once SP receives the artifact, it calls the IDP's ArtifactResolutionService (ARS) endpoint to exchange the artifact for the full content.
The artifact token is an opaque identifier ( meaning some random string to represent an 'ID') transported in the HTTP response from IDP to SP. Then the exchange of artifacts for full response content happens on a backend socket channel, which is NOT HTTP.
SOAP Binding
This binding, as its name, uses SOAP (Simple Object Access Protocol) messaging framework to transport SAML messages. This is less used today as well.
SP-Initiated Flow with HTTP POST Binding
Since HTTP POST Binding is mostly used nowadays, let's take a look at the SP-Initiated flow again, but this time with more details.

SP-Initiated Flow with HTTP POST Binding
When a user accesses the service from SP, SP detects no active user session exists, so it redirects user to IDP for authentication. Note here a SAML Request is generated by SP and forwarded to IDP's SingleSignOnService Endpoint via HTTP POST.
SingleSignOnService Endpoint is the target at IDP to invoke the SAML flow and HTTP POST is a binding method, i.e. how SAML requests should be sent from SP to IDP. Although there are other binding methods, e.g. HTTP Redirect and Artifact Binding, it is HTTP POST that is mostly used. Then let's understand this SAML Request with more details.
SAML Request
A SAML Request (or AuthnRequest) is a message from SP to IDP, requesting IDP to issue a SAML Response describing the properties of a user after the user authenticates to the IDP. This happens in the SP-Initiated flow.
Here is an example SAML Request in the XML format:

Some key elements are highlighted.
- Version - Indicates it is SAML 2.0
- IssueInstant - The date and time the SAML request was issued. This field is used to ensure that the message is not replayed or reused after a certain period of time
- Destination - The entityID of the IDP that this message is supposed to be sent to
- Protocol Binding - The binding method used to transmit SAML messages
- AssertionConsumerServiceURL - The ACS URL at SP where IDP will return the SAML response to
- Issuer - The entityID of SP
- SignatureValue - The signature value (redacted in the example) of the SAML request
- X509Certificate - The public cert (redacted in the example) that can be used to verify the signature of this request
- NameIDPolicy - The NameIDFormat that IDP should use in the SAML Response
- RequestedAuthnContext - The level of authentication that is required by the SP. This may include information such as authentication method, strength of authentication and any additional context needed
Not all elements listed above are required and from time to time, some of the elements are omitted. For example, if AssertionConsumerServiceURL is not specified in the request, IDP usually has a default one that's preconfigured for this SP during metadata exchange, and when sending the SAML Response back, it will use the default AssertionConsumerServiceURL.
The signature information is not required in the SAML Request, but is always good to have. In this case, IDP can always verify the signature using the Public Cert provided (how to verify signature is outside the scope of this post) to make sure the request is not tampered.
The NameIDFormat is important too, as it depicts how the subject value (the value that identifies the user authenticated to IDP) returned in the SAML response should be interpreted by SP. For example, it's shown as 'emailAddress' in the example, so in the SAML response, the subject value should be interpreted as an email value.
RequestedAuthnContext provides a means for SP to ask IDP to authenticate the user with a specific authentication mechanism. For example, if SP specifies PasswordProtectedTransport in the SAML Request, the IDP knows it has to authenticate the user through login/password, protected by SSL/TLS. In turn, IDP will also show in the SAML response which mechanism it used to authenticate the user through AuthnContextClassRef. AuthnContextClassRef is required in the SAML Response.
SAML Response and Assertion
Once the browser sends the SAML Request to IDP, it will ask the user to login to IDP (if no active user session is presented). Once a user is authenticated to IDP, it will pull the user profile from the User Directory and generate a SAML Response, which will be sent back to SP's ACS endpoint.
The format of SAML Response is similar to SAML Request. However, the major component in SAML Response is the SAML Assertion.
SAML Assertion
A SAML Assertion is a part of the SAML where all necessary user profile information e.g. email, first name, last name, role etc, as well as the authentication context/status are present.
Here is an Assertion example:

Some key elements are highlighted:
- Issuer - The entityID of IDP
- Subject - The user who has been authenticated, presented in a specified NameIDFormat
- NotOnOrAfter - Indicate how long this assertion will be valid for
- Conditions - Conditions that must be met for the assertion to be considered valid
- Audience - The entityID of the target SP who this message is intended for
- AuthnContext - The level of authentication context that happened with this user authentication
- Attribute - List of additional user attributes such as first name, last name, role etc.
As you can see, with the authentication contexts and identity profiles presented in the assertion, SP who receives that information has what is necessary to confirm a user identity. Yet, to properly send the SAML Assertion back to SP, it needs a wrapper following the SAML protocol.
SAML Response
An example SAML Response looks like below. Assertion is still the main part, but there are some other added entries to make it a valid SAML Response.

Highlighted elements:
- Response - Indicate this is a SAML response instead of SAML request
- Issuer - The entityID of IDP
- SignatureValue - The signature value for the entire SAML response message
- X509Certificate - The public certificate that is used to verify the signature
- StatusCode - The status of the SAML flow, success, requestDenied and etc.
Once the SP receives the SAML response and verifies the signature to make sure of the data integrity, SP can extract identity information from the Assertion and create a user session and set browser cookie.
IDP-Initiated Flow with HTTP POST Binding
The IDP-Initiated Flow is similar to the SP-Initiated Flow, with less steps.
IDP-Initiated flow is used from time to time. This could be based on various reasons. For example, IDP just finishes some other function and would like to trigger the SAML flow, or SP doesn't support SP-Initiated flow well.
Regarding the flow, instead of accessing SP, the browser directly accesses IDP and a login page is present. Once a user finishes authentication at IDP, the remaining steps are the same as in SP-Initiated flow.

One thing to note is that IDP needs to know which SP to forward the SAML Response to if there are multiple SP. This could be done by passing a URL parameter to IDP when triggering the IDP-initiated flow or other means that IDP supports.