SAML Single Logout

Implement SAML Single Logout and understand its session boundaries

AuthOS release 0.8.2 API v1 Latest-only documentation
Updated Jul 15, 2026 Edit this page

GET/POST /saml/:org_slug/:service_slug/slo

SAML Single Logout (SLO) endpoint. Receives a LogoutRequest from the Service Provider, invalidates the user’s sessions, and returns a signed LogoutResponse. This endpoint enables global session termination across federated services.

Authentication: None required (public endpoint)

Path Parameters:

Parameter Type Description
org_slug string Organization slug
service_slug string Service slug

Query/Form Parameters:

Parameter Type Required Description
SAMLRequest string Yes Base64-encoded (optionally deflated) SAML LogoutRequest
RelayState string No Opaque value to be returned to SP after logout

Example Request (HTTP-Redirect binding):

# This request is typically initiated by the Service Provider when user logs out
# User's browser is redirected to:
https://sso.example.com/saml/acme-corp/main-app/slo?SAMLRequest=nZFBa4MwGIb%2FSsh...&RelayState=https://sp.example.com/logout

Example Request (HTTP-POST binding):

<form method="post" action="https://sso.example.com/saml/acme-corp/main-app/slo">
  <input type="hidden" name="SAMLRequest" value="PHNhbWxwOkxvZ291dFJlcXVlc3Q..." />
  <input type="hidden" name="RelayState" value="https://sp.example.com/logout" />
</form>

Response: HTML page with auto-submitting form containing LogoutResponse

Response Body (HTML):

<!DOCTYPE html>
<html>
<head>
    <title>Logging out...</title>
    <style>
        body { font-family: sans-serif; background: #f5f5f5; padding: 20px; text-align: center; }
        .container { max-width: 400px; margin: 50px auto; background: white; padding: 40px; border-radius: 8px; }
        .spinner { border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%;
                   width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 20px auto; }
        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
    </style>
</head>
<body onload="document.forms[0].submit()">
    <div class="container">
        <div class="spinner"></div>
        <h2>Logging out...</h2>
        <p>Please wait while we complete the logout process.</p>
    </div>
    <form method="post" action="https://sp.example.com/slo" style="display: none;">
        <input type="hidden" name="SAMLResponse" value="PHNhbWxwOkxvZ291dFJlc3BvbnNl..." />
        <input type="hidden" name="RelayState" value="https://sp.example.com/logout" />
        <noscript>
            <p>JavaScript is disabled. Please click the button below to continue.</p>
            <input type="submit" value="Continue" />
        </noscript>
    </form>
</body>
</html>

Single Logout Flow:

  1. Service Provider Initiates Logout:

    • User clicks “Logout” in the Service Provider (e.g., Salesforce)
    • SP generates a SAML LogoutRequest containing the user’s NameID
    • User’s browser is redirected to IdP’s SLO endpoint
  2. IdP Processes LogoutRequest:

    • Decodes and parses LogoutRequest XML
    • Extracts request ID, issuer, and NameID (user identifier)
    • Validates destination matches expected SLO endpoint
    • Identifies user from NameID (typically email address)
  3. Session Invalidation:

    • IdP attempts to invalidate the user’s sessions for the specific service
    • Clears session tokens and refresh tokens
    • Logs the logout event for audit purposes
  4. LogoutResponse Generation:

    • IdP creates a SAML LogoutResponse with Success status
    • Response includes InResponseTo referencing the original request ID
    • Response is signed according to service configuration
  5. Return to Service Provider:

    • User’s browser auto-submits LogoutResponse to SP’s SLO URL
    • SP validates the response signature
    • SP confirms logout is complete
    • The Service Provider handles the response; operators must verify resulting session state in both systems

SAML LogoutRequest Structure:

<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                     xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                     ID="_request_123"
                     Version="2.0"
                     IssueInstant="2025-01-15T10:30:00Z"
                     Destination="https://sso.example.com/saml/acme-corp/main-app/slo">
  <saml:Issuer>https://acme.my.salesforce.com</saml:Issuer>
  <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user@example.com</saml:NameID>
</samlp:LogoutRequest>

SAML LogoutResponse Structure (Generated by IdP):

<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                      ID="_response_456"
                      Version="2.0"
                      IssueInstant="2025-01-15T10:30:05Z"
                      Destination="https://acme.my.salesforce.com/slo"
                      InResponseTo="_request_123">
  <saml:Issuer>https://sso.example.com/saml/acme-corp/main-app</saml:Issuer>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <!-- XML signature -->
  </Signature>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
</samlp:LogoutResponse>

NameID Format Support:

  • urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress (default) - Uses user email
  • urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress - Uses user email
  • urn:oasis:names:tc:SAML:2.0:nameid-format:persistent - Uses user ID or email (context-dependent)
  • urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified - Attempts email or user ID match

Error Responses:

  • 400 Bad Request: Invalid or missing SAMLRequest, malformed XML, missing NameID
    {
      "error": "SAMLRequest parameter is required"
    }
    
    {
      "error": "NameID is required"
    }
    
    {
      "error": "No SLO URL configured and no issuer in request"
    }
    
  • 403 Forbidden: Organization not active, SAML not enabled
  • 404 Not Found: Service not found
  • 500 Internal Server Error: No active signing key, encryption service unavailable

Important Considerations:

Session Scope:

  • Only invalidates sessions for the specific service (not all services)
  • User remains logged in to other Service Providers
  • User remains logged in to the IdP platform itself

User Not Found:

  • If NameID doesn’t match any user, SLO still returns Success status
  • This prevents information disclosure about valid users
  • Logged as warning for administrative review

SLO URL Resolution:

  • Uses configured slo_url from service SAML configuration
  • Falls back to issuer URL from LogoutRequest if SLO URL not configured
  • Ensure SLO URL is properly configured for reliable logout flow

Security Features:

  • Request validation and signature verification (if signed by SP)
  • Response signing with IdP’s private key
  • InResponseTo correlation for request-response matching
  • RelayState preservation for SP state management
  • Destination validation to prevent request forgery
  • Support for both HTTP-POST and HTTP-Redirect bindings

Configuration Requirements:

To enable SLO, ensure:

  1. SAML is enabled for the service
  2. Active signing certificate exists
  3. slo_url is configured (optional but recommended)
  4. Service Provider is configured with IdP’s SLO endpoint from metadata

Example Configuration:

curl -X POST https://sso.example.com/api/organizations/acme-corp/services/main-app/saml \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "entity_id": "https://acme.my.salesforce.com",
    "acs_url": "https://acme.my.salesforce.com/services/auth/saml/AssertionConsumerService",
    "slo_url": "https://acme.my.salesforce.com/services/auth/saml/SingleLogoutService",
    "name_id_format": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
    "sign_assertions": true,
    "sign_response": true
  }'

Governance considerations:

  • SLO can contribute to a global-session-termination workflow
  • Session invalidation events can contribute to an operator’s audit evidence
  • Operators must validate IdP interoperability, failure handling, offboarding completeness, and applicable control requirements
  • This capability does not make a deployment SOC 2, ISO 27001, or GDPR compliant