# SAML integration

OpenIAM supports SAML 2.0 in two distinct roles:

* **OpenIAM as IdP** — OpenIAM authenticates users and sends SAML assertions to external Service Providers (e.g., Salesforce, AWS, a custom app)
* **OpenIAM as SP** — OpenIAM delegates authentication to an external Identity Provider (e.g., ADFS, Okta, Azure AD) and accepts their assertions

Both roles are configured in the same Admin UI area (Auth Providers) but use different provider types.

## Concepts

<table><thead><tr><th width="140.66668701171875">Term</th><th>Meaning</th></tr></thead><tbody><tr><td><strong>IdP</strong></td><td>Identity Provider — authenticates the user and issues the SAML assertion</td></tr><tr><td><strong>SP</strong></td><td>Service Provider — the application that relies on the IdP for authentication</td></tr><tr><td><strong>Assertion</strong></td><td>Signed XML blob containing the user's identity and attributes</td></tr><tr><td><strong>AuthnRequest</strong></td><td>XML message the SP sends to the IdP to initiate login</td></tr><tr><td><strong>ACS URL</strong></td><td>Assertion Consumer Service URL — the SP endpoint that receives the SAMLResponse</td></tr><tr><td><strong>Metadata</strong></td><td>XML document describing an IdP or SP (endpoints, certificates, NameID formats)</td></tr><tr><td><strong>JIT</strong></td><td>Just-in-Time provisioning — creating/updating a user on first SAML login</td></tr></tbody></table>

## OpenIAM as IdP

In this role OpenIAM:

* Receives `AuthnRequest` from an SP (or initiates SSO itself)
* Authenticates the user (login page, MFA, etc.)
* Issues a signed `SAMLResponse` with an `Assertion` back to the SP's ACS URL

### Creating a SAML IdP Provider

To create SAML IdP provider, log in to **Webconsole** and navigate to **Access Control** → **Authentication Providers** → **+ New Provider** → **Type:** SAML Identity Provider

{% stepper %}
{% step %}

### Fill in the required information fields

<table><thead><tr><th width="226">Field</th><th width="106.3333740234375">Required</th><th>Description</th></tr></thead><tbody><tr><td><strong>Name</strong></td><td>Yes</td><td>Human-readable label (e.g., <code>Salesforce – Prod</code>)</td></tr><tr><td><strong>Managed System</strong></td><td>Yes</td><td>The managed system this provider is linked to</td></tr><tr><td><strong>Assertion Consumer URL</strong></td><td>Yes</td><td>The SP's ACS URL — where OpenIAM will POST the SAMLResponse</td></tr><tr><td><strong>Request Issuer</strong></td><td>Yes</td><td>The <code>EntityID</code> of this IdP configuration (used in the assertion's <code>&#x3C;Issuer></code>)</td></tr><tr><td><strong>Response Issuer</strong></td><td>No</td><td>Overrides the <code>&#x3C;Issuer></code> in the SAMLResponse (defaults to Request Issuer)</td></tr><tr><td><strong>Audiences</strong></td><td>No</td><td>Audience restrictions added to <code>&#x3C;AudienceRestriction></code> in the assertion</td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure signing and encryption

<table><thead><tr><th width="252.33331298828125">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Sign Metadata</strong></td><td>Include an <code>&#x3C;ds:Signature></code> element in the published metadata</td></tr><tr><td><strong>Signing Algorithm</strong></td><td>e.g., <code>RSA-SHA256</code> (<code>http://www.w3.org/2001/04/xmldsig-more#rsa-sha256</code>)</td></tr><tr><td><strong>Canonicalization Algorithm</strong></td><td>e.g., <code>Exclusive C14N</code> (<code>http://www.w3.org/2001/10/xml-exc-c14n#</code>)</td></tr><tr><td><strong>Digest Algorithm</strong></td><td>e.g., <code>SHA-256</code> (<code>http://www.w3.org/2001/04/xmlenc#sha256</code>)</td></tr><tr><td><strong>Want Assertions Signed</strong></td><td>Sign the <code>&#x3C;Assertion></code> element inside the response</td></tr><tr><td><strong>Want Response Signed</strong></td><td>Sign the outer <code>&#x3C;Response></code> element</td></tr><tr><td><strong>Public / Private Key</strong></td><td>X.509 certificate + PKCS8 private key used for signing (and optionally encryption)</td></tr><tr><td><strong>Send Encrypted Assertion</strong></td><td>Encrypt the <code>&#x3C;Assertion></code> element before sending</td></tr><tr><td><strong>Data Encryption Algorithm</strong></td><td>Symmetric algorithm for assertion encryption (e.g., AES-256-CBC)</td></tr><tr><td><strong>Key Encryption Algorithm</strong></td><td>Algorithm for wrapping the symmetric key (e.g., RSA-OAEP)</td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure authentication

<table><thead><tr><th width="223.66668701171875">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Auth Context Class Ref</strong></td><td>Value placed in <code>&#x3C;AuthnContextClassRef></code> (e.g., <code>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</code>)</td></tr><tr><td><strong>Protected by 2FA</strong></td><td>Force MFA challenge before issuing the assertion</td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure NameID format

<table><thead><tr><th width="213.6666259765625">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>NameID Format</strong></td><td>Format of the Subject NameID (see <a href="#nameid-formats">NameID Formats</a>)</td></tr><tr><td><strong>NameID Qualifier</strong></td><td>Optional qualifier to scope the NameID value</td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure single logout

<table><thead><tr><th width="261">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Logout URL</strong></td><td>SP's SLO endpoint — where OpenIAM sends <code>LogoutRequest</code> / <code>LogoutResponse</code></td></tr><tr><td><strong>Logout Binding</strong></td><td><code>POST</code> or <code>Redirect</code></td></tr><tr><td><strong>Want Logout Requests Signed</strong></td><td>Require the SP to sign its <code>LogoutRequest</code> messages</td></tr></tbody></table>
{% endstep %}

{% step %}

### Attribute mapping

Add rows to the attribute table to include user attributes in the assertion's `<AttributeStatement>`:

<table><thead><tr><th width="213">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>SAML Attribute Name</strong></td><td>The <code>Name</code> attribute in the <code>&#x3C;saml:Attribute></code> element</td></tr><tr><td><strong>Data Type</strong></td><td><code>String</code>, <code>Integer</code>, <code>Boolean</code>, <code>Date</code>, <code>DateTime</code>, <code>URI</code>, <code>Base64</code>, <code>HexBinary</code></td></tr><tr><td><strong>Source</strong></td><td>One of: <strong>User Attribute</strong> (pick from resource attributes), <strong>Static Value</strong>, <strong>Groovy Script</strong></td></tr></tbody></table>
{% endstep %}

{% step %}

### Advanced / Customization

<table><thead><tr><th width="253.66668701171875">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Post-Processor Groovy Script</strong></td><td>Runs after the assertion is built; can modify or add attributes</td></tr><tr><td><strong>NameID Resolver Groovy Script</strong></td><td>Custom logic to compute the NameID value for the subject</td></tr><tr><td><strong>RelayState</strong></td><td>Static value or Groovy-generated; echoed back through the SAML flow</td></tr><tr><td><strong>Enable Chaining</strong></td><td>Pass the request on to another auth provider after this one</td></tr></tbody></table>
{% endstep %}

{% step %}

### Save and share metadata

Click **Save**, then copy the **Metadata URL** and share it with the SP administrator:

```
IdP Metadata URL:
  https://{host}/idp/saml2/idp/metadata/{providerId}

IdP-Initiated SSO URL:
  https://{host}/idp/saml2/idp/initiate/{providerId}
```

Most SPs support automatic metadata import via URL. If the SP requires a file, download the XML from the metadata URL and upload it.
{% endstep %}
{% endstepper %}

## IdP endpoints reference

All endpoints are on the IDP module. Base URL: `https://{host}/idp`

<table><thead><tr><th width="311.6666259765625">Endpoint</th><th width="160.33331298828125">Method</th><th>Description</th></tr></thead><tbody><tr><td><code>/saml2/idp/metadata/{providerId}</code></td><td>GET / POST</td><td>SAML IdP Metadata (EntityDescriptor XML)</td></tr><tr><td><code>/saml2/idp/login</code></td><td>GET / POST</td><td>SP-initiated SSO — receives <code>SAMLRequest</code> (AuthnRequest)</td></tr><tr><td><code>/saml2/idp/login/{randomId}</code></td><td>GET / POST</td><td>SP-initiated SSO with session-specific ID</td></tr><tr><td><code>/saml2/idp/initiate/{id}</code></td><td>GET / POST</td><td>IdP-initiated SSO — no AuthnRequest required</td></tr><tr><td><code>/saml2/idp/logout</code></td><td>GET / POST</td><td>SLO — receives <code>LogoutRequest</code> from SP or <code>LogoutResponse</code> from other IdP</td></tr><tr><td><code>/saml2/idp/globalLogout</code></td><td>GET / POST</td><td>Initiates global logout across all active SPs in the session</td></tr></tbody></table>

### IdP-Initiated SSO Flow

{% stepper %}
{% step %}

### User navigates to the IdP-initiated SSO URL

```
GET https://{host}/idp/saml2/idp/initiate/{providerId}
(optionally: ?RelayState=https://app.example.com/dashboard)
```

{% endstep %}

{% step %}

### OpenIAM authenticates the user

OpenIAM authenticates the user (login page if no session).
{% endstep %}

{% step %}

### OpenIAM builds SAMLResponse

{% code overflow="wrap" expandable="true" %}

```
<Response Destination="{assertionConsumerURL}" ID="..." IssueInstant="...">
  <Issuer>{responseIssuer}</Issuer>
  <Status><StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></Status>
  <Assertion>
    <Issuer>...</Issuer>
    <Subject>
      <NameID Format="{nameIdFormat}">{userId}</NameID>
    </Subject>
    <Conditions NotBefore="..." NotOnOrAfter="...">
      <AudienceRestriction><Audience>{audience}</Audience></AudienceRestriction>
    </Conditions>
    <AuthnStatement AuthnInstant="...">
      <AuthnContext>
        <AuthnContextClassRef>{authContextClassRef}</AuthnContextClassRef>
      </AuthnContext>
    </AuthnStatement>
    <AttributeStatement>
      <Attribute Name="email"><AttributeValue>jane@example.com</AttributeValue></Attribute>
      <!-- additional mapped attributes -->
    </AttributeStatement>
  </Assertion>
</Response>
```

{% endcode %}
{% endstep %}

{% step %}

### OpenIAM auto-submits the response to the SP

```
POST {assertionConsumerURL}
SAMLResponse=<base64-encoded SAMLResponse>
RelayState=<value>
```

{% endstep %}
{% endstepper %}

### SP-Initiated SSO Flow (IdP side)

{% stepper %}
{% step %}

### SP redirects the user to OpenIAM

```
GET https://{host}/idp/saml2/idp/login
?SAMLRequest=<base64+deflate-encoded AuthnRequest>
&RelayState=<opaque value>
&SigAlg=...
&Signature=...     (if SP signs the request)
```

{% endstep %}

{% step %}

### OpenIAM validates the AuthnRequest

OpenIAM decodes and validates the AuthnRequest.
{% endstep %}

{% step %}

### User authenticates

User authenticates (login page / MFA / existing session).
{% endstep %}

{% step %}

### OpenIAM posts the SAMLResponse to the SP's ACS URL

OpenIAM POSTs SAMLResponse to the SP's ACS URL (same as step 3-4 above).
{% endstep %}
{% endstepper %}

### Single Logout (IdP side)

**SP-initiated SLO:**

{% stepper %}
{% step %}

### SP sends LogoutRequest to OpenIAM

```
POST /saml2/idp/logout
SAMLRequest=<base64-encoded LogoutRequest>
```

{% endstep %}

{% step %}

### OpenIAM terminates the user's session

OpenIAM terminates the user's session.
{% endstep %}

{% step %}

### OpenIAM notifies other SPs

OpenIAM sends LogoutRequest to each other SP that was part of this session.
{% endstep %}

{% step %}

### OpenIAM sends the final LogoutResponse

After all SPs acknowledge (LogoutResponse), OpenIAM sends final LogoutResponse back to the initiating SP.
{% endstep %}
{% endstepper %}

**OpenIAM-initiated global logout:**

```
GET /saml2/idp/globalLogout
→ OpenIAM sends LogoutRequest to all SPs in the session, then terminates it.
```

## OpenIAM as SP

In this role OpenIAM:

* Redirects or POSTs an `AuthnRequest` to the external IdP's SSO endpoint
* Receives the `SAMLResponse` (assertion) at its ACS endpoint
* Validates the assertion and creates an authenticated session
* Optionally provisions the user on first login (JIT)

### Creating a SAML SP provider

Creating a SAML SP provider, log in to **Webconsole** and navigate to **Access Control** → **Authentication Providers** → **+ New Provider** → **Type:** SAML Service Provider

{% stepper %}
{% step %}

### Fill in the required information

<table><thead><tr><th width="217.33331298828125">Field</th><th width="112.333251953125">Required</th><th>Description</th></tr></thead><tbody><tr><td><strong>Name</strong></td><td>Yes</td><td>Human-readable label (e.g., <code>Azure AD – Corp</code>)</td></tr><tr><td><strong>Managed System</strong></td><td>Yes</td><td>The managed system representing this external IdP</td></tr><tr><td><strong>Authentication Policy</strong></td><td>Yes</td><td>Policy applied after successful SAML login</td></tr><tr><td><strong>Password Policy</strong></td><td>Yes</td><td>Password policy assigned to JIT-provisioned users</td></tr><tr><td><strong>Request Issuer</strong></td><td>Yes</td><td>The <code>EntityID</code> of this SP — sent as <code>&#x3C;Issuer></code> in the AuthnRequest</td></tr><tr><td><strong>SAML Issuer Format</strong></td><td>Yes</td><td>Format URI for the issuer element (e.g., <code>urn:oasis:names:tc:SAML:2.0:nameid-format:entity</code>)</td></tr><tr><td><strong>Login URL</strong></td><td>Yes</td><td>The external IdP's SSO endpoint URL</td></tr><tr><td><strong>Login Binding</strong></td><td>Yes</td><td><code>POST</code> or <code>Redirect</code> (how the AuthnRequest is sent to the IdP)</td></tr><tr><td><strong>Include Destination in AuthnRequest</strong></td><td>No</td><td>Adds a <code>Destination</code> attribute to the AuthnRequest XML</td></tr></tbody></table>
{% endstep %}

{% step %}

### Signing

<table><thead><tr><th width="305">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Sign Metadata</strong></td><td>Sign the SP metadata document</td></tr><tr><td><strong>Sign AuthnRequests</strong></td><td>Include a signature on outgoing <code>AuthnRequest</code> messages</td></tr><tr><td><strong>Want Assertions Signed</strong></td><td>Reject assertions that are not signed by the IdP</td></tr><tr><td><strong>Signing Algorithm / Canonicalization / Digest</strong></td><td>Same algorithms as IdP (must match what the external IdP expects)</td></tr><tr><td><strong>Public / Private Key</strong></td><td>SP's key pair for signing AuthnRequests and decrypting encrypted assertions</td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure authentication

<table><thead><tr><th width="221">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Auth Context Class Ref</strong></td><td>Value requested in <code>&#x3C;RequestedAuthnContext></code> in the AuthnRequest</td></tr></tbody></table>
{% endstep %}

{% step %}

### NameID Format

<table><thead><tr><th width="285">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>NameID Format in SAML Request</strong></td><td>Format URI requested in <code>&#x3C;NameIDPolicy></code> in the AuthnRequest</td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure single logout

<table><thead><tr><th width="158.33331298828125">Field</th><th width="106">Required</th><th>Description</th></tr></thead><tbody><tr><td><strong>Logout URL</strong></td><td>Yes</td><td>External IdP's SLO endpoint — where OpenIAM sends <code>LogoutRequest</code></td></tr><tr><td><strong>Logout Binding</strong></td><td>Yes</td><td><code>POST</code> or <code>Redirect</code></td></tr></tbody></table>
{% endstep %}

{% step %}

### Attribute mapping

Same table as the IdP case, but here the mappings define **how incoming assertion attributes are written to the OpenIAM user profile**:

<table><thead><tr><th width="206.3333740234375">Column</th><th>Description</th></tr></thead><tbody><tr><td><strong>SAML Attribute Name</strong></td><td>The attribute <code>Name</code> to extract from the incoming assertion</td></tr><tr><td><strong>Data Type</strong></td><td>Expected data type</td></tr><tr><td><strong>Source</strong></td><td>Target: <strong>User Attribute</strong> (maps to a user field), <strong>Static Value</strong>, or <strong>Groovy Script</strong></td></tr></tbody></table>
{% endstep %}

{% step %}

### Advanced / Customization

<table><thead><tr><th width="262.33331298828125">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>JIT SAML Authenticator Script</strong></td><td>Groovy script run on first login to create or update the user (see <a href="#just-in-time-user-provisioning">JIT</a>)</td></tr><tr><td><strong>Post-Processor Groovy Script</strong></td><td>Runs after assertion validation; can enrich the session</td></tr><tr><td><strong>RelayState</strong></td><td>Static value or Groovy-generated; preserves the original request URL</td></tr><tr><td><strong>Enable Chaining</strong></td><td>Pass authentication on to another provider after this one</td></tr></tbody></table>
{% endstep %}

{% step %}

### Save and share metadata

```
SP Metadata URL:
  https://{host}/idp/saml2/sp/metadata/{providerId}

SP ACS URL:
  https://{host}/idp/saml2/sp/login

SP SLO URL:
  https://{host}/idp/saml2/sp/logout/{providerId}
```

Provide the metadata URL (or downloaded XML) to the external IdP administrator so they can register OpenIAM as a trusted SP.
{% endstep %}
{% endstepper %}

### SP Endpoints reference

<table><thead><tr><th>Endpoint</th><th width="117">Method</th><th>Description</th></tr></thead><tbody><tr><td><code>/saml2/sp/metadata/{providerId}</code></td><td>GET</td><td>SP Metadata (EntityDescriptor XML)</td></tr><tr><td><code>/saml2/sp/login</code></td><td>GET</td><td>Generates and sends <code>AuthnRequest</code> to the external IdP</td></tr><tr><td><code>/saml2/sp/login</code></td><td>POST</td><td><strong>ACS</strong> — receives <code>SAMLResponse</code> from the external IdP</td></tr><tr><td><code>/saml2/sp/logout/{providerId}</code></td><td>GET / POST</td><td>Initiates SLO — sends <code>LogoutRequest</code> to the external IdP</td></tr><tr><td><code>/saml2/sp/logout</code></td><td>GET / POST</td><td>Receives <code>LogoutRequest</code> or <code>LogoutResponse</code> from the external IdP</td></tr></tbody></table>

### SP-Initiated SSO flow

{% stepper %}
{% step %}

### User tries to access a protected resource

User tries to access a resource protected by the SAML SP provider.
{% endstep %}

{% step %}

### OpenIAM generates an AuthnRequest

```
<AuthnRequest
  Destination="{loginURL}"
  ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
  AssertionConsumerServiceURL="https://{host}/idp/saml2/sp/login">
  <Issuer>{requestIssuer}</Issuer>
  <NameIDPolicy Format="{nameIdFormatInSAMLRequest}" AllowCreate="true"/>
  <RequestedAuthnContext>
    <AuthnContextClassRef>{authContextClassRef}</AuthnContextClassRef>
  </RequestedAuthnContext>
</AuthnRequest>
```

{% endstep %}

{% step %}

### OpenIAM sends the request to the external IdP

OpenIAM redirects (or POSTs) the user to the IdP's Login URL with `SAMLRequest=<base64+deflate(AuthnRequest)>` and `RelayState`.
{% endstep %}

{% step %}

### External IdP authenticates the user

External IdP authenticates the user and POSTs SAMLResponse to:

```
POST https://{host}/idp/saml2/sp/login
SAMLResponse=<base64-encoded response>
RelayState=<value>
```

{% endstep %}

{% step %}

### OpenIAM validates the response

* Verifies IdP signature
* Checks Issuer, Conditions (NotBefore/NotOnOrAfter), AudienceRestriction
* Decrypts assertion (if encrypted)
* Extracts attributes
  {% endstep %}

{% step %}

### JIT provisioning runs if needed

If the user is unknown and JIT is configured → runs JIT script.
{% endstep %}

{% step %}

### OpenIAM creates the session and redirects

OpenIAM creates an authenticated session and redirects to RelayState or default URL.
{% endstep %}
{% endstepper %}

## Just-in-Time user provisioning

When a user logs in via an external IdP for the first time (or on every login to keep attributes in sync), the **JIT SAML Authenticator Script** (Groovy) is invoked.

The script receives the full set of assertion attributes and can:

* Look up the user by email/username
* Create a new user if not found
* Update profile attributes (name, department, roles, etc.)
* Return the resolved `userId` for session creation

Configure the script in **Authentication Provider** → **Customization** → JIT SAML Authenticator Groovy Script.

### Single Logout (SP side)

**SP-initiated SLO:**

{% stepper %}
{% step %}

### User logs out from OpenIAM

User logs out from OpenIAM.
{% endstep %}

{% step %}

### OpenIAM sends LogoutRequest to the external IdP

```
POST/Redirect → {logoutURL}
SAMLRequest=<base64-encoded LogoutRequest>
```

{% endstep %}

{% step %}

### External IdP responds with LogoutResponse

```
POST https://{host}/idp/saml2/sp/logout
SAMLResponse=<base64-encoded LogoutResponse>
```

{% endstep %}

{% step %}

### OpenIAM terminates the local session

OpenIAM terminates the local session.
{% endstep %}
{% endstepper %}

**IdP-initiated SLO:**

{% stepper %}
{% step %}

### External IdP sends LogoutRequest to OpenIAM

```
POST https://{host}/idp/saml2/sp/logout
SAMLRequest=<base64-encoded LogoutRequest>
```

{% endstep %}

{% step %}

### OpenIAM terminates the local session and responds

OpenIAM terminates the local session and sends LogoutResponse back.
{% endstep %}
{% endstepper %}

## Shared configuration

### Certificates and signing

Each SAML provider (IdP or SP) has its own X.509 certificate + private key pair.

**In the Admin UI:**

* Upload or paste the **Public Certificate** (PEM format)
* Upload or paste the **Private Key** (PKCS8 PEM format)
* Or click **Generate** to create a self-signed key pair

The public certificate is embedded in the provider's metadata `<KeyDescriptor>` element so the other party can verify signatures.

**Recommended signing configuration:**

<table><thead><tr><th width="170.66668701171875">Algorithm</th><th>Recommended value</th></tr></thead><tbody><tr><td>Signing</td><td><code>http://www.w3.org/2001/04/xmldsig-more#rsa-sha256</code> (RSA-SHA256)</td></tr><tr><td>Canonicalization</td><td><code>http://www.w3.org/2001/10/xml-exc-c14n#</code> (Exclusive C14N)</td></tr><tr><td>Digest</td><td><code>http://www.w3.org/2001/04/xmlenc#sha256</code> (SHA-256)</td></tr></tbody></table>

### Attribute mapping

The **Attribute Mapping Table** is present on both IdP and SP providers.

**On an IdP provider** — defines which attributes are included in the outgoing assertion.

│ │

<table><thead><tr><th width="189.6666259765625">SAML Attribute Name</th><th width="134.3333740234375">Data type</th><th>Source</th></tr></thead><tbody><tr><td><code>email</code></td><td>String</td><td>User Attribute → <code>user.email</code></td></tr><tr><td><code>firstName</code></td><td>String</td><td>User Attribute → <code>user.firstName</code></td></tr><tr><td><code>department</code></td><td>String</td><td>User Attribute → <code>user.department</code></td></tr><tr><td><code>role</code></td><td>String</td><td>Groovy Script → (compute from groups)</td></tr><tr><td><code>env</code></td><td>String</td><td>Static Value → production</td></tr></tbody></table>

**On an SP provider** — defines how incoming assertion attributes are written back to the user.

<table><thead><tr><th width="259.6666259765625">SAML Attribute Name</th><th width="134">Data type</th><th>Source</th></tr></thead><tbody><tr><td><code>http://schemas.../givenname</code></td><td>String</td><td>User Attribute → <code>user.firstName</code></td></tr><tr><td><code>http://schemas.../surname</code></td><td>String</td><td>User Attribute → <code>user.lastName</code></td></tr><tr><td><code>http://schemas.../groups</code></td><td>String</td><td>Groovy Script → (assign roles)</td></tr></tbody></table>

### NameID Formats

<table><thead><tr><th width="176">Format</th><th>URI</th></tr></thead><tbody><tr><td>Persistent</td><td><code>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</code></td></tr><tr><td>Transient</td><td><code>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</code></td></tr><tr><td>Email Address</td><td><code>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</code></td></tr><tr><td>X.509 Subject</td><td><code>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</code></td></tr><tr><td>Windows Domain</td><td><code>urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName</code></td></tr><tr><td>Kerberos</td><td><code>urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos</code></td></tr><tr><td>Entity</td><td><code>urn:oasis:names:tc:SAML:2.0:nameid-format:entity</code></td></tr><tr><td>Unspecified</td><td><code>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</code></td></tr></tbody></table>

* **IdP** — set `NameID Format` to control what format the issued assertion uses
* **SP** — set `NameID Format in SAML Request` to request a specific format from the external IdP

### Bindings

<table><thead><tr><th width="142.33331298828125">Binding</th><th width="339.3333740234375">Description</th><th>Typical use</th></tr></thead><tbody><tr><td><strong>HTTP POST</strong></td><td>SAMLRequest / SAMLResponse in an auto-submitted HTML form body</td><td>Large assertions, SLO responses</td></tr><tr><td><strong>HTTP Redirect</strong></td><td>SAMLRequest as a deflated, base64-encoded URL query parameter</td><td>AuthnRequest (lighter payload)</td></tr></tbody></table>

Most SPs and IdPs support both. POST is the default in OpenIAM.

### Metadata Import / Export

Instead of filling in every field manually, you can import an existing metadata XML:

**On the IdP provider form:**

* **Generate from SP Metadata** — upload the SP's metadata XML; OpenIAM extracts the ACS URL, certificate, NameID formats, and SLO URL
* **Generate from IdP Metadata** — upload another IdP's metadata for chaining scenarios

**On the SP provider form:**

* **Generate from IdP Metadata** — upload the external IdP's metadata XML; OpenIAM extracts the SSO URL, certificate, SLO URL, and NameID formats

**Admin REST API for metadata import:**

```
# IdP provider: import from SP metadata
POST /rest/api/authprovider/saml/idp/keys/generateFromSPMetadata
Content-Type: multipart/form-data
(file: SP metadata XML)

# SP provider: import from IdP metadata
POST /rest/api/authprovider/saml/sp/keys/generateFromIDPMetadata
Content-Type: multipart/form-data
(file: IdP metadata XML)
```

### Provider chaining

A SAML provider can forward authentication to another provider in sequence:

* **IdP → SP chain**: the IdP provider authenticates the user, then passes the session to an SP provider that calls an upstream IdP
* **SP → IdP chain**: after receiving an assertion from an upstream IdP, pass the authenticated session to a local IdP provider that issues its own assertion to a downstream SP

Configure in:

```
Auth Provider → Advanced → Enable Chaining → Next Auth Provider (select)
```

### RelayState strategy

RelayState is an opaque string passed through the SAML flow to preserve context (e.g., the original page the user was trying to reach).

<table><thead><tr><th width="158">Option</th><th>Description</th></tr></thead><tbody><tr><td><strong>Static Value</strong></td><td>Always use the same fixed string</td></tr><tr><td><strong>Groovy Script</strong></td><td>Compute the value dynamically per request (receives request context)</td></tr></tbody></table>

## Field reference

### Common Fields

<table><thead><tr><th width="244.66668701171875">Field</th><th width="120.33331298828125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>requestIssuer</code></td><td>String</td><td><code>EntityID</code> sent as <code>&#x3C;Issuer></code> in outgoing messages</td></tr><tr><td><code>signingAlgorithm</code></td><td>String (URI)</td><td>XML signature algorithm</td></tr><tr><td><code>canonicalizationAlgorithm</code></td><td>String (URI)</td><td>XML canonicalization algorithm</td></tr><tr><td><code>digestAlgorithm</code></td><td>String (URI)</td><td>XML digest algorithm</td></tr><tr><td><code>authContextClassRef</code></td><td>String (URI)</td><td>Authentication context class reference</td></tr><tr><td><code>logoutBinding</code></td><td>Enum</td><td><code>POST</code> or <code>Redirect</code> for SLO messages</td></tr><tr><td><code>logoutURL</code></td><td>String</td><td>SLO endpoint of the other party</td></tr><tr><td><code>wantAssertionsSigned</code></td><td>Boolean</td><td>Require <code>&#x3C;Assertion></code> to be signed</td></tr><tr><td><code>signAuthnRequests</code></td><td>Boolean</td><td>Sign outgoing <code>AuthnRequest</code> messages</td></tr><tr><td><code>nameIdResolverGroovyScriptId</code></td><td>String</td><td>Script ID for custom NameID computation</td></tr><tr><td><code>postProcessGroovyScriptId</code></td><td>String</td><td>Script ID for post-assertion processing</td></tr><tr><td><code>relayStateStaticValue</code></td><td>String</td><td>Fixed RelayState value</td></tr><tr><td><code>relayStateGeneratorGroovyScriptId</code></td><td>String</td><td>Script ID for dynamic RelayState</td></tr><tr><td><code>chainingEnabled</code></td><td>Boolean</td><td>Forward to another provider after this one</td></tr><tr><td><code>nextAuthProviderId</code></td><td>String</td><td>ID of the next provider in the chain</td></tr></tbody></table>

### IdP-specific fields

<table><thead><tr><th width="308.33331298828125">Field</th><th width="152.3333740234375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>assertionConsumerURL</code></td><td>String</td><td>SP's ACS URL — destination for the SAMLResponse</td></tr><tr><td><code>responseIssuer</code></td><td>String</td><td><code>&#x3C;Issuer></code> value in the SAMLResponse (overrides requestIssuer)</td></tr><tr><td><code>audiences</code></td><td>List&#x3C;String></td><td>Audience URIs in <code>&#x3C;AudienceRestriction></code></td></tr><tr><td><code>nameIdFormat</code></td><td>String (URI)</td><td>NameID format used in the issued assertion</td></tr><tr><td><code>nameQualifier</code></td><td>String</td><td>NameID qualifier / scope</td></tr><tr><td><code>sendEncryptedAssertion</code></td><td>Boolean</td><td>Encrypt the <code>&#x3C;Assertion></code> element</td></tr><tr><td><code>dataEncryptionAssertionAlgorithm</code></td><td>String (URI)</td><td>Symmetric encryption algorithm for assertion</td></tr><tr><td><code>keyEncryptionAssertionAlgorithm</code></td><td>String (URI)</td><td>Key-wrapping algorithm for the symmetric key</td></tr><tr><td><code>protectedBy2FA</code></td><td>Boolean</td><td>Require 2FA before issuing the assertion</td></tr><tr><td><code>wantResponseSigned</code></td><td>Boolean</td><td>Sign the outer <code>&#x3C;Response></code> element (in addition to <code>&#x3C;Assertion></code>)</td></tr></tbody></table>

### SP-specific fields

<table><thead><tr><th width="327.66668701171875">Field</th><th width="130.33331298828125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>loginURL</code></td><td>String</td><td>External IdP's SSO endpoint URL</td></tr><tr><td><code>loginBinding</code></td><td>Enum</td><td><code>POST</code> or <code>Redirect</code> for the outgoing AuthnRequest</td></tr><tr><td><code>samlIssuerFormat</code></td><td>String (URI)</td><td>Format URI for the <code>&#x3C;Issuer></code> element in the AuthnRequest</td></tr><tr><td><code>nameIdFormatInSAMLRequest</code></td><td>String (URI)</td><td>NameID format requested in <code>&#x3C;NameIDPolicy></code></td></tr><tr><td><code>includeDestinationInAuthnRequest</code></td><td>Boolean</td><td>Add <code>Destination</code> attribute to the AuthnRequest</td></tr><tr><td><code>justInTimeSAMLAuthenticatorScriptId</code></td><td>String</td><td>JIT provisioning Groovy script ID</td></tr><tr><td><code>authPolicyId</code></td><td>String</td><td>Authentication policy applied after successful login</td></tr><tr><td><code>policyId</code></td><td>String</td><td>Password policy for JIT-provisioned users</td></tr><tr><td><code>wantAssertionsSigned</code></td><td>Boolean</td><td>Reject unsigned assertions from the IdP</td></tr></tbody></table>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs-beta.openiam.com/federation/saml-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
