> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.id.me/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.id.me/_mcp/server.

# Keycloak SAML integration guide

> Configure Keycloak to use ID.me as a SAML 2.0 identity provider for federated authentication.

## Overview

This guide provides steps to integrate Keycloak with ID.me using the SAML 2.0 protocol.

**Intended audience**
Developers and IAM administrators responsible for configuring federation between Keycloak and ID.me.

**What you will build**
A federated authentication flow where Keycloak delegates user authentication to ID.me using SAML 2.0 assertions.

**Result**
A federated SAML authentication flow where Keycloak delegates authentication to ID.me, allowing users to sign in to a target application.

**Identity proofing behavior**
Authentication behavior, identity verification settings, and returned attributes are driven by ID.me policy configurations.

## Authentication flow

The following steps outline the SAML authentication flow between the user, Keycloak, and ID.me:

The user navigates to the application and is redirected to the Keycloak login page

The user selects the **ID.me** option

Keycloak generates a SAML AuthnRequest and redirects the user to the ID.me SSO URL

The user completes authentication and identity verification at ID.me

ID.me returns a SAML Response containing the signed assertion to the Keycloak ACS URL

Keycloak validates the assertion, creates a user session, and posts a new SAML assertion to your application's ACS URL. Your application validates the assertion and grants the user access.

## Prerequisites

* A running instance of Keycloak
* Administrator access to the Keycloak admin console
* An ID.me sandbox account for testing your integration
* Understanding of [SAML flows](/guides/saml/overview) and terminology

## Environments

ID.me provides two environments:

#### Sandbox

`https://api.idmelabs.com/`

#### Production

`https://api.id.me/`

> **Note**
>
> All ID.me OIDC and SAML endpoints are derived from the base URL above. For production, replace the sandbox base URL in every ID.me endpoint you configure.

### Examples

* OIDC issuer (Sandbox): `https://api.idmelabs.com/oidc`
* OIDC issuer (Production): `https://api.id.me/oidc`
* SAML metadata URL (Sandbox): `https://api.idmelabs.com/saml/metadata`
* SAML metadata URL (Production): `https://api.id.me/saml/metadata`

## Configure Keycloak

### Create a realm

Log in to the Keycloak admin console (default `http://localhost:8080`)

Select the realm dropdown in the top left corner (the default is “Master”)

Select **Create Realm**

Enter a **Realm name** (for example, `myrealm`)

Select **Create**

### Configure ID.me as a SAML identity provider

Navigate to **Identity Providers** in the left menu.

Select **Add provider** > **SAML 2.0**.

Fill in the following fields. When you enter the SAML entity descriptor URL and tab out of the field, Keycloak fetches the ID.me metadata and auto-populates the remaining SAML settings.

| Field                      | Value                                             |
| -------------------------- | ------------------------------------------------- |
| Alias                      | `idme-sandbox-saml`                               |
| Display Name               | `IDMe-Sandbox`                                    |
| Service Provider Entity ID | `http://localhost:8080/realms/<your realm name>`  |
| Use entity descriptor      | `On`                                              |
| SAML entity descriptor     | `https://api.idmelabs.com/saml/metadata/provider` |

Select **Show metadata** to expand and review the values Keycloak auto-populated from the ID.me metadata URL. Most fields are populated correctly from the metadata. Verify or update the following fields:

| Field                              | Auto-populated value / expected value                                             |
| ---------------------------------- | --------------------------------------------------------------------------------- |
| Identity provider entity ID        | `api.idmelabs.com`                                                                |
| Single Sign-On service URL         | `https://api.idmelabs.com/saml/SingleSignOnService`                               |
| Single logout service URL          | `https://api.idmelabs.com/saml/SingleLogoutService`                               |
| NameID policy format               | `Unspecified`                                                                     |
| Allow create                       | `On`                                                                              |
| HTTP-POST binding response         | `On`                                                                              |
| HTTP-POST binding for AuthnRequest | `On`                                                                              |
| Want AuthnRequests signed          | `On`                                                                              |
| Signature algorithm                | `RSA_SHA256`                                                                      |
| SAML signature key name            | `KEY_ID`                                                                          |
| Validate Signatures                | `On`                                                                              |
| Validating X509 Certificates       | The **active** X.509 certificate from ID.me SAML metadata (without header/footer) |
| Comparison                         | `exact`                                                                           |
| AuthNContextClassRefs              | `<your ID.me policy handle value>` (e.g., nist_ial2_aal2 in this guide)           |

> **Warning**
>
> By default, Keycloak may auto-populate an inactive certificate from the ID.me metadata URL because ID.me uses an `active=true` XML element during certificate transitions to avoid downtime. Keycloak ignores that custom XML element, so you must manually verify that the active ID.me signing certificate is entered in the Validating X509 Certificates field.

Select **Add**

### Map user claims

Navigate to **Identity Providers** > **\<your IdP Name>** > **Mappers**

Select **Add mapper**

Configure the mapper:

* **Name**: An identifier for the mapping (for example, `firstName`)
* **Sync mode override**: Select `Force` (always overwrite from ID.me at login)
* **Mapper type**: Select `Attribute Importer`
* **Attribute Name**: Enter the exact SAML attribute name coming from ID.me
* **Name Format**: `ATTRIBUTE_FORMAT_BASIC`
* **User Attribute name**: The attribute in Keycloak that will store the imported value (for example, `firstName` or a custom attribute)

Select **Save**

Repeat these steps for other claims as necessary (e.g., `lname` to `lastName`, `email` to `email`, `uuid` to `uuid`).

## Configure a target app

This step registers your SAML service provider (SP) application as a client in Keycloak. Use the entity ID and ACS URL from your SP's metadata.

> **Note**
>
> The examples in this guide use a custom Python SAML SP demo application for illustrative purposes. It runs locally on port 8081. Substitute your own SP's entity ID, ACS URL, and base URL where indicated.

Navigate to **Clients** > **Create Client**

Set **Client type** to `SAML`

Enter a **Client ID** matching your SP's entity ID (for example, `http://localhost:8081/saml/metadata`)

Select **Next**, then **Save**

Configure the client settings:

| Section                  | Field                      | Value                                                                                                        |
| ------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------ |
| General settings         | Name                       | Your application name (for example, `SAMLTestApp`)                                                           |
| Access settings          | Root URL                   | Your SP's base URL (for example, `http://localhost:8081`)                                                    |
| Access settings          | Valid redirect URIs        | Your SP's ACS URL (for example, `http://localhost:8081/*`). Do NOT use wildcards in production environments. |
| Access settings          | Master SAML Processing URL | Your SP's ACS URL (for example, `http://localhost:8081/saml/acs`)                                            |
| SAML capabilities        | Name ID format             | `username`                                                                                                   |
| SAML capabilities        | Force POST binding         | `On`                                                                                                         |
| SAML capabilities        | Include AuthnStatement     | `On`                                                                                                         |
| Signature and Encryption | Sign documents             | `On`                                                                                                         |
| Signature and Encryption | Sign assertions            | `On`                                                                                                         |
| Signature and Encryption | Signature algorithm        | `RSA_SHA256`                                                                                                 |
| Signature and Encryption | Canonicalization method    | `EXCLUSIVE`                                                                                                  |

Go to the **Keys** tab, enable **Client signature required**, and import your SP's signing certificate using the **Certificate PEM** format.

## Map attributes to the target app

Keycloak does not automatically include user attributes in the assertion it sends to your SP. You must add mappers to the client's dedicated scope.

Navigate to **Clients** > **\<your client>** > **Client scopes** tab

Select the dedicated scope link (named after your client entity ID with `-dedicated` appended)

Select **Configure a new mapper** > **User Attribute**

Configure the mapper:

| Name        | User Attribute | SAML Attribute Name | NameFormat |
| ----------- | -------------- | ------------------- | ---------- |
| `firstName` | `firstName`    | `fname`             | `Basic`    |
| `lastName`  | `lastName`     | `lname`             | `Basic`    |
| `email`     | `email`        | `email`             | `Basic`    |
| `uuid`      | `uuid`         | `uuid`              | `Basic`    |

The **User Attribute** column is the field name Keycloak stored the value in from your IdP mappers. The **SAML Attribute Name** is the attribute name that will appear in the assertion sent to your SP.

Select **Save** and repeat for each attribute you want included in the assertion.

> **Warning**
>
> If your SP receives a SAML assertion with a duplicate attribute name error, the `role_list` default client scope may be conflicting with your custom mappers. Navigate to **Clients** > **\<your client>** > **Client scopes** and change `role_list` from `Default` to `None` to remove it from this client.

## Configure ID.me

This portion of the configuration is completed by an ID.me Solution Consultant. You will need to provide the following information to complete the setup:

**Assertion Consumer Service (ACS) URL**

The Keycloak ACS URL follows this pattern: \
`http://localhost:8080/realms/<your-realm-name>/broker/<your external IDP alias>/endpoint`

**SP Entity ID**

The Keycloak SP Entity ID (Handle) follows this pattern: \
`http://localhost:8080/realms/<your realm name>`

**Policy handle name**

Confirm the ID.me policy handle with your Solution Consultant. This value determines the identity verification level and attributes returned in the SAML assertion, and is configured in Keycloak as your `AuthNContextClassRef`.

**Keycloak signing certificate**

You must provide your Keycloak signing certificate (in PEM format) to your Solution Consultant. You can find this in Keycloak under **Realm Settings** > **Keys** (Algorithm: RS256, Type: RSA, Use: SIG).

## Test the integration

Navigate to your SP's login initiation URL (for example, `http://localhost:8081/initiate?forceAuthn=true` in this guide).

On the Keycloak login page, select the button for your external IdP (for example, **IDMe-Sandbox**).

Complete authentication and identity verification at ID.me per your policy settings

Verify you are redirected back to Keycloak and then from Keycloak to your SP's ACS URL with a valid assertion from Keycloak. In this guide, the sample Python app displays the ID.me attributes returned in the assertion including `fname`, `lname`, `email`, `uuid`.

In your Keycloak admin console, verify the new user appears under **Users**.

## Troubleshooting

**You do not see your configurations**

Always ensure you are in the correct realm. Each time you log in, Keycloak defaults to the master realm.

**User not created in Keycloak**

This can occur due to missing attribute mappings or a misconfigured login flow. Check your mappers and ensure your "First Login Flow" setting is correct.

**Assertion validation failed**

This typically happens because of clock skew or an incorrect ACS URL. Check the timestamps and verify the ACS URL in your configuration.

**AuthnRequest rejected by ID.me**

This often points to a Keycloak signing certificate mismatch. Verify that the certificate uploaded to ID.me matches the **active** signing certificate in Keycloak under **Realm Settings** > **Keys** > **RS256**.

**ID.me assertion not trusted by Keycloak**

Keycloak does not evaluate the `active=true` attribute in ID.me metadata during ingestion of the ID.me metadata and may auto-populate an inactive certificate. In such cases, you must manually enter the ID.me signing certificate labled with the `active=true` element from the ID.me metadata.

**ID.me rejects unsigned request**

Keycloak is likely not signing AuthnRequests. Enable **Want AuthnRequests Signed** on the Identity Provider configuration in Keycloak.

**User auto-provisioning on first login**

With the default first broker login flow, Keycloak auto-creates users upon their first successful login.

**Attribute mappers required for each claim**

Keycloak does not automatically map SAML assertion attributes to user fields. You must create a mapper for each attribute you want stored in Keycloak.

**Invalid requester error from Keycloak**

The Client ID configured in Keycloak does not match the entity ID your SP sends in the AuthnRequest. Verify that the Client ID in **Clients** > your client > **Settings** matches your SP's entity ID exactly (for example, `http://localhost:8081/saml/metadata`).

**Duplicate attribute name error in SP assertion**

The `role_list` default client scope adds a `Role` attribute that conflicts with custom mappers when attribute names collide. Navigate to **Clients** > your client > **Client scopes** and change `role_list` from **Default** to **None** to remove it from this client.

**Attributes missing from SP assertion**

No mappers are configured on the dedicated client scope, so Keycloak does not include user attributes in the assertion it sends to your SP. Navigate to **Clients** > your client > **Client scopes** > the dedicated scope (named after your client entity ID with `-dedicated` appended) and add a User Attribute mapper for each attribute you want included.