Azure SAML 2.0 Partner API authentication

Azure SAML 2.0 authentication enables applications to authenticate users using SAML 2.0 with Azure Active Directory (Azure AD) as the Identity Provider (IdP). This process involves a sequence of HTTP requests between the service provider (SP) and Azure AD, enabling a secure exchange of authentication information.

This guide covers the SAML authentication flow in detail, including the HTTP requests involved and an example of a working implementation.


1. Overview of SAML 2.0 Authentication Process

In SAML 2.0 authentication, there are three main parties involved:

  1. Identity Provider (IdP) – Azure AD in this case, which authenticates the user and provides a SAML token (assertion).
  2. Service Provider (SP) – The application or API that uses Azure AD for authentication.
  3. User Agent – Typically the browser, which handles redirection and request submission.

Key Components of SAML Authentication Flow

  • Authentication Request: Sent by the SP to the IdP to initiate authentication.
  • SAML Response: Returned by the IdP to the SP, containing the user’s SAML assertion.
  • SAML Assertion: The authentication token, embedded within the SAML Response, that includes user identity and claims.

2. Step-by-Step SAML Authentication Flow with HTTP Requests

Step 1: Service Provider (SP) Initiates Authentication

When the user tries to access a resource on the SP (partner application or API), the SP must first verify the user’s identity by redirecting them to the Azure AD SAML endpoint.

HTTP Request: Authentication Redirect (SP → IdP)

The SP redirects the user’s browser to the IdP (Azure AD) with an HTTP GET or POST request. This request includes a SAML Authentication Request (AuthnRequest), encoded in Base64, containing:

  • Issuer: Identifies the SP.
  • Assertion Consumer Service (ACS) URL: URL where the IdP sends the SAML response.
  • Request ID: Unique identifier for tracking the request.
  • SAML Version: Specifies the SAML version (2.0).
  • Signature (optional): The request may be signed for additional security.

Sample HTTP Redirect to IdP

GET https://login.microsoftonline.com/{tenant-id}/saml2 HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

SAMLRequest=base64_encoded_authnRequest
&RelayState=unique_session_identifier
  • SAMLRequest: Contains the Base64-encoded AuthnRequest XML.
  • RelayState: Optional parameter to maintain the session state between SP and IdP. This will be returned to the SP with the SAML response.

Sample SAML AuthnRequest XML (Base64-encoded for the request)

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_uniqueID"
    Version="2.0" IssueInstant="2023-10-31T09:00:00Z"
    Destination="https://login.microsoftonline.com/{tenant-id}/saml2"
    AssertionConsumerServiceURL="https://sp.example.com/saml/acs">
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://sp.example.com/</saml:Issuer>
</samlp:AuthnRequest>

Step 2: IdP (Azure AD) Authenticates the User

After receiving the AuthnRequest, Azure AD presents a login page to the user (if not already logged in). The user provides their credentials, and Azure AD authenticates them.

Step 3: Azure AD Issues a SAML Response

Once authenticated, Azure AD generates a SAML Response containing the SAML Assertion, which includes the user’s identity and claims. Azure AD signs this response to ensure it hasn’t been tampered with and sends it back to the SP’s ACS endpoint via the user’s browser.

HTTP POST: SAML Response (IdP → SP)

Azure AD sends an HTTP POST response back to the SP’s ACS URL, containing:

  • SAMLResponse: Base64-encoded XML containing the SAML Assertion.
  • RelayState: The RelayState value passed from the original request to maintain state.

Sample HTTP POST Response to ACS

POST https://sp.example.com/saml/acs HTTP/1.1
Host: sp.example.com
Content-Type: application/x-www-form-urlencoded

SAMLResponse=base64_encoded_saml_response
&RelayState=unique_session_identifier

The SAMLResponse parameter includes a Base64-encoded XML document containing the assertion:

Sample SAML Response XML (Base64-decoded)

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    ID="_uniqueResponseID" InResponseTo="_uniqueID" Version="2.0" IssueInstant="2023-10-31T09:02:00Z">
    <saml:Issuer>https://login.microsoftonline.com/{tenant-id}/</saml:Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_uniqueAssertionID"
        IssueInstant="2023-10-31T09:02:00Z" Version="2.0">
        <saml:Issuer>https://login.microsoftonline.com/{tenant-id}/</saml:Issuer>
        <saml:Subject>
            <saml:NameID>user@example.com</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData NotOnOrAfter="2023-10-31T09:07:00Z"
                    Recipient="https://sp.example.com/saml/acs" InResponseTo="_uniqueID"/>
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2023-10-31T09:00:00Z" NotOnOrAfter="2023-10-31T09:07:00Z">
            <saml:AudienceRestriction>
                <saml:Audience>https://sp.example.com/</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AttributeStatement>
            <saml:Attribute Name="email">
                <saml:AttributeValue>user@example.com</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="role">
                <saml:AttributeValue>Admin</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>
  • SAML Assertion: Contains user details, including claims and attributes like email and role.
  • Signature: Azure AD digitally signs the SAML Response to ensure its authenticity.

Step 4: SP Validates the SAML Response and Assertion

Upon receiving the SAML Response, the SP performs the following checks:

  1. Signature Validation:
  • Verifies the SAML Response signature against Azure AD’s public key (available from the Azure AD metadata).
  1. Audience Validation:
  • Ensures the Audience in the assertion matches the SP’s Identifier.
  1. Conditions and Time Constraints:
  • Checks the NotBefore and NotOnOrAfter conditions to ensure the assertion is still valid.
  1. Extract Attributes and Claims:
  • Retrieves user attributes (claims) from the SAML Assertion and uses them for authorization.

If all checks are successful, the SP grants the user access.


3. Example: SAML Authentication for a Partner API

Suppose a partner API requires users to authenticate via SAML 2.0 with Azure AD as the IdP. Here’s how it works:

  1. SP Initiates Authentication:
  • The user navigates to the API, and the SP redirects the user to Azure AD’s SAML endpoint with an AuthnRequest.
  1. User Authenticates at Azure AD:
  • The user enters their credentials, and Azure AD verifies them.
  1. Azure AD Issues a SAML Response:
  • After successful authentication, Azure AD issues a SAML Response and sends it to the SP’s ACS URL.
  1. SP Validates the SAML Response:
  • The SP validates the response, verifies the user’s identity, and allows access to the API if successful.

Sample Python Code for SAML Validation (Simplified)

This example demonstrates validating a SAML Response in a Python-based SP:

from xml.etree import ElementTree
import base64

def validate_saml_response(encoded_response):
    # Decode the SAML Response
    saml_response_xml = base64.b64decode(encoded_response).decode("utf-8")

    # Parse the SAML XML
    tree = ElementTree.fromstring(saml_response_xml)

    # Extract the Issuer, Audience, and Conditions
    issuer = tree.find(".//saml:Issuer", namespaces={"saml": "urn:oasis:n

ames:tc:SAML:2.0:assertion"}).text
    audience = tree.find(".//saml:Audience", namespaces={"saml": "urn:oasis:names:tc:SAML:2.0:assertion"}).text
    not_on_or_after = tree.find(".//saml:SubjectConfirmationData", namespaces={"saml": "urn:oasis:names:tc:SAML:2.0:assertion"}).get("NotOnOrAfter")

    # Validate Conditions, Audience, and Issuer
    if issuer != "https://login.microsoftonline.com/{tenant-id}/":
        raise ValueError("Invalid Issuer")
    if audience != "https://sp.example.com/":
        raise ValueError("Invalid Audience")
    if not_on_or_after < datetime.utcnow().isoformat():
        raise ValueError("Token expired")

    # Extract user claims (e.g., email)
    email = tree.find(".//saml:Attribute[@Name='email']/saml:AttributeValue", namespaces={"saml": "urn:oasis:names:tc:SAML:2.0:assertion"}).text
    return email

# Example usage
encoded_response = "base64_encoded_saml_response"
user_email = validate_saml_response(encoded_response)
print("Authenticated user:", user_email)

This guide shows how Azure AD enables secure, standards-based SSO and federated access to partner applications and APIs using SAML 2.0. By following these steps, organizations can effectively authenticate users and maintain secure access across multiple applications.

Author: tonyhughes