> ## Documentation Index
> Fetch the complete documentation index at: https://bifrost-backport-mcp-oauth2-server.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# SSO using OIDC

> Configure Keycloak as your identity provider for Bifrost Enterprise using OpenID Connect.

## Prerequisites

* A running Keycloak server (self-hosted or cloud) with admin access to a realm
* Bifrost Enterprise deployed and accessible
* Your Bifrost callback URL: `https://<your-bifrost-domain>/login`

***

## Step 1: Create an OIDC Client

<Steps>
  <Step title="Open the Clients list">
    In the Keycloak Admin Console, select your realm from the top-left dropdown.

    Go to **Clients** in the left nav and click **Create client**.

    <Frame caption="The Clients list - click Create client to start.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-create-client.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=e2f3dad8b15a1e114d944857b51dd5a5" alt="Keycloak Admin Console Clients list with Create client button highlighted" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-create-client.png" />
    </Frame>
  </Step>

  <Step title="Fill in General settings">
    Set the following fields:

    * **Client type**: OpenID Connect
    * **Client ID**: `bifrost-oidc` (or any identifier you prefer)
    * **Name**: `Bifrost`

    Click **Next**.

    <Frame caption="General settings - set Client type to OpenID Connect and provide a Client ID.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-client-creation.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=978112f2771895f6b25ed3050647eb25" alt="Keycloak Create client General settings form with Client type OpenID Connect, Client ID bifrost-oidc, and Name Bifrost" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-client-creation.png" />
    </Frame>
  </Step>

  <Step title="Configure Capability config">
    On the **Capability config** step, enable:

    * **Client authentication** - makes this a confidential client and generates a client secret
    * **Standard flow** - enables Authorization Code login
    * **Service accounts roles** - required for Bifrost to call the Keycloak Admin REST API for background user sync

    Leave all other toggles at their defaults. Click **Next**.
  </Step>

  <Step title="Configure Login settings">
    Set your redirect URIs:

    * **Root URL**: `https://<your-bifrost-domain>`
    * **Valid redirect URIs**: `https://<your-bifrost-domain>/login`

    Optionally, to use Discover Claims during setup, also add:

    ```
    https://<your-bifrost-domain>/workspace/scim/oauth-discover-callback
    ```

    Click **Save**.

    <Frame caption="Login settings - add your Bifrost login URL and optionally the Discover Claims callback URI.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-login-settings.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=3e8a7f46d4867665875089a9c42389b3" alt="Keycloak Login settings form with Root URL, Valid redirect URIs showing the Bifrost login and oauth-discover-callback URLs" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-login-settings.png" />
    </Frame>
  </Step>

  <Step title="Grant Admin REST API permissions to the service account">
    The client is now saved. Open it and go to the **Service accounts roles** tab.

    Click **Assign role**, filter by `realm-management`, and assign:

    | Role | Required |
    | - | - |
    | `view-users` | Required - lets Bifrost list and import users |
    | `view-realm` | Recommended - enables group and role listing |
    | `query-groups` | Optional - needed for group-based import filters |

    These permissions power the **Sync Users from Keycloak** import flow in [Optional Next Steps](#optional-next-steps).
  </Step>
</Steps>

***

## Step 2: Copy Your Client Secret

<Steps>
  <Step title="Open the Credentials tab">
    Open the **bifrost-oidc** client and go to the **Credentials** tab.

    Copy the **Client Secret** - you will need it in [Step 5](#step-5-configure-bifrost).

    <Frame caption="Credentials tab - copy the Client Secret.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-client-config.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=765dd860b77d64f8527f82cba3a25478" alt="Keycloak Credentials tab showing Client Authenticator set to Client Id and Secret with the Client Secret field" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-client-config.png" />
    </Frame>
  </Step>
</Steps>

***

## Step 3: Configure Claim Mappers

Keycloak does not include realm roles or full group paths in tokens by default. Add two mappers to the client's dedicated scope.

<Steps>
  <Step title="Open the dedicated scope">
    In the **bifrost-oidc** client, go to the **Client scopes** tab.

    Click on the **bifrost-oidc-dedicated** scope.

    <Frame caption="Client scopes tab - open the dedicated scope to add mappers.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-client-scopes.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=82b391f766c0d9654ad56ee66ae0a057" alt="Keycloak Client scopes tab with bifrost-oidc-dedicated scope highlighted" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-client-scopes.png" />
    </Frame>
  </Step>

  <Step title="Add the Group Membership mapper">
    Click **Add mapper** → **By configuration**.

    <Frame caption="Configure a new mapper - select Group Membership from the list.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-configure-new-mapper.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=72279668929035bf8afa337e6c82817d" alt="Keycloak Configure a new mapper dialog showing mapper type list with Group Membership visible" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-configure-new-mapper.png" />
    </Frame>

    Select **Group Membership** and configure it:

    | Field | Value |
    | - | - |
    | **Name** | `Groups` |
    | **Token Claim Name** | `groups` |
    | **Full group path** | **On** |
    | **Add to ID token** | **On** |
    | **Add to access token** | **On** |
    | **Add to userinfo** | **On** |

    Click **Save**.

    <Frame caption="Group Membership mapper - Full group path must be On so Bifrost receives paths like /Engineering instead of just Engineering.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-groups-mapping.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=673c25cec2d797d6c3be2b9391ba7083" alt="Group Membership mapper form with Name Groups, Token Claim Name groups, Full group path On, and all Add to token toggles On" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-groups-mapping.png" />
    </Frame>

    <Note>
      Keep **Full group path** enabled. Keycloak sends groups as paths (e.g. `/Engineering`, `/Platform`). Bifrost's `/${*}` wildcard in team mappings extracts the name after the slash automatically - see [Step 5](#step-5-configure-bifrost).
    </Note>
  </Step>

  <Step title="Add the User Realm Role mapper">
    Click **Add mapper** → **By configuration** again.

    Select **User Realm Role** from the list.

    <Frame caption="Select User Realm Role from the mapper list to expose realm roles in the JWT.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-realm-role-mapping.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=9d2844b92b2152a08c0443ce5e6e7f84" alt="Keycloak Configure a new mapper dialog with User Realm Role option highlighted" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-realm-role-mapping.png" />
    </Frame>

    Configure it:

    | Field | Value |
    | - | - |
    | **Name** | `realm_roles` |
    | **Token Claim Name** | `realm_access.roles` |
    | **Claim JSON Type** | String |
    | **Multivalued** | **On** |
    | **Add to ID token** | **On** |
    | **Add to access token** | **On** |

    Click **Save**.

    <Frame caption="User Realm Role mapper - Token Claim Name realm_access.roles matches the dotted path Bifrost uses for role lookup.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/keycloak-realm-role-config.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=84549958737d592a3757510b667437f7" alt="User Realm Role mapper form with Name realm_roles, Token Claim Name realm_access.roles, Multivalued On, and Add to ID and access token enabled" width="3024" height="1660" data-path="media/user-provisioning/keycloak/keycloak-realm-role-config.png" />
    </Frame>
  </Step>
</Steps>

***

## Step 4: Assign Users

In Keycloak, users need to be assigned to the realm roles and groups you plan to map in Bifrost.

* Go to **Users** → select a user → **Role mapping** tab → assign the relevant realm roles (e.g. `realm-admin`, `bifrost-viewer`)
* Go to **Users** → select a user → **Groups** tab → join the relevant groups (e.g. `/Engineering`, `/Platform`)

***

## Step 5: Configure Bifrost

<Steps>
  <Step title="Open User Provisioning and choose Keycloak">
    In your Bifrost dashboard, go to **Governance** → **User Provisioning**.

    Select **Keycloak** as the identity provider and click **Next**.

    <Frame caption="Select Keycloak from the list of identity providers.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/bifrost-user-provisioning.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=31635e1e3eef8d02d787156bf7c7a14a" alt="Bifrost Choose Provider screen with Keycloak card selected" width="3024" height="1666" data-path="media/user-provisioning/keycloak/bifrost-user-provisioning.png" />
    </Frame>
  </Step>

  <Step title="Fill in the provider configuration">
    Enter the details from the previous steps:

    * **Server URL**: your Keycloak base URL - no `/realms/...` suffix (e.g. `https://keycloak.company.com`)
    * **Realm**: your realm name (e.g. `Bifrost`)
    * **Client ID**: the client ID you set in Step 1 (e.g. `bifrost-oidc`)
    * **Client Secret**: copied from [Step 2](#step-2-copy-your-client-secret)
    * **Audience**: optional - leave blank to default to the Client ID
    * **Team IDs Field (Optional)**: leave as `groups` to match the mapper you created in Step 3

    Click **Verify & Next** to confirm the connection.

    <Frame caption="Provider Configuration - enter your Keycloak Server URL, Realm, Client ID, and Client Secret.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/bifrost-keycloak-provider-config.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=ff67802bb8649a68c80d73799972f5c2" alt="Bifrost Provider Configuration form for Keycloak with Server URL, Realm, Client ID, Client Secret, and Team IDs Field filled in" width="3024" height="1666" data-path="media/user-provisioning/keycloak/bifrost-keycloak-provider-config.png" />
    </Frame>
  </Step>

  <Step title="Discover claims">
    On the Attribute Mapping screen, click **Discover Claims**.

    Bifrost opens a sign-in popup with your Keycloak realm - no session is created.

    Once you authenticate, it returns the exact claims your Keycloak tenant is sending in the JWT. Confirm that `groups` and `realm_access.roles` appear before building your mappings.

    <Frame caption="Discover Claims shows the live JWT from Keycloak - confirm groups (full paths) and realm_access.roles are present.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/bifrost-keycloak-discover-claims.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=111b88388cb8e5b90ed668382a5057ce" alt="Bifrost Discover Claims screen showing claims including email, groups with /Engineering and /Platform paths, and realm_access with roles array" width="3024" height="1668" data-path="media/user-provisioning/keycloak/bifrost-keycloak-discover-claims.png" />
    </Frame>
  </Step>

  <Step title="Set up attribute mappings">
    Use the sections below the claim list to map Keycloak claim values to Bifrost roles, teams, and business units.

    **Attribute-to-Role Mappings**

    Map a claim value to a Bifrost role. All matching rules are evaluated. If several rules match, Bifrost picks one using your chosen resolution strategy:

    * **The role with the most permissions** (default)
    * **The first matching role, by list order** (drag rows to set priority)

    If no rule matches, no role is assigned and login is denied.

    Example: map `realm_access.roles` → `realm-admin` → **Admin**, and `realm_access.roles` → `bifrost-viewer` → **Viewer**.

    **Attribute-to-Team Mappings**

    Map a claim value to a Bifrost team. All matching rules apply. Three value formats work:

    * **Exact value** - e.g. `/Engineering` maps that specific group to a fixed team name
    * **`*`** - syncs the claim value directly as the team name
    * **`/${*}`** - extracts the group name from Keycloak's full group path - e.g. `/${*}` matches `/Engineering` and creates team **Engineering**, and matches `/Platform` and creates team **Platform**

    **Attribute-to-Business Unit Mappings**

    Same wildcard support as team mappings. Three value formats work:

    * **Exact value** - maps a specific claim value to a fixed business unit name
    * **`*`** - syncs the claim value directly as the business unit name
    * **`/${*}`** - extracts the group name from Keycloak's full group path, same as team mappings (e.g. `/${*}` on `/Engineering` → business unit **Engineering**)
    * When a rule matches, the resolved business unit is assigned to the user. All matching rules apply, so a user can belong to several business units at once
    * A business unit you assign by hand is never removed by a sync, and one granted from a claim stays even if that claim later stops appearing - remove it by hand or change the mapping

    <Frame caption="Attribute Mapping - role rules use realm_access.roles, team rules use groups with /${*} to extract the team name from Keycloak's full group path.">
      <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/bifrost-keycloak-attribute-mapping.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=7d2b45e0e94b3636b7f8c340963d56cc" alt="Bifrost Attribute Mapping screen showing realm_access.roles mapped to Admin and Viewer roles, and groups mapped with /${*} wildcard to extract team names" width="3024" height="1670" data-path="media/user-provisioning/keycloak/bifrost-keycloak-attribute-mapping.png" />
    </Frame>

    Click **Next** when done.
  </Step>

  <Step title="Review and enable">
    Review your configuration on the final screen and click **Enable**.

    <Warning>
      Restart your Bifrost server after enabling for the changes to take effect.
    </Warning>
  </Step>
</Steps>

***

## Optional Next Steps

**Import users from Keycloak** - once SSO is configured, you can bulk-import users from Keycloak into Bifrost without waiting for each user to log in. Go to **Governance** → **Users** → **Sync Users from Keycloak** and filter by group or realm role to preview and import matching users.

<Frame caption="Sync Users from Keycloak - filter by group membership or realm role to select which users to import into Bifrost.">
  <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/bifrost-sync-users.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=525620ef9a7f289a3f79a0f56a327f91" alt="Sync Users from IdP dialog showing Filter by Groups with Engineering, Operations, and Platform checkboxes, and Filter by Roles section" width="3024" height="1670" data-path="media/user-provisioning/keycloak/bifrost-sync-users.png" />
</Frame>

Imported users appear in **Governance** → **Users** with their role and team assignments applied immediately.

<Frame caption="Users page after syncing - users are marked Managed by Keycloak and receive their roles and teams from the attribute mappings.">
  <img src="https://mintcdn.com/bifrost-backport-mcp-oauth2-server/A90L-7LUIbib_k1z/media/user-provisioning/keycloak/bifrost-users-page.png?fit=max&auto=format&n=A90L-7LUIbib_k1z&q=85&s=6c64723a1bfc54768337f79516477d26" alt="Bifrost Users page showing a user with Admin role and Engineering and Platform teams, marked Managed by Keycloak" width="3024" height="1670" data-path="media/user-provisioning/keycloak/bifrost-users-page.png" />
</Frame>

***

## Troubleshooting

**`serverUrl must not include /realms/{realm}`** - the Server URL field takes the base Keycloak URL only. Set the realm separately in the Realm field. Example: `https://keycloak.company.com` + Realm `Bifrost` - not `https://keycloak.company.com/realms/Bifrost`.

**Users are redirected back to login** - confirm the client's **Valid redirect URIs** exactly match your Bifrost login URL (trailing slash matters). Verify the client is **Enabled** in Keycloak.

**Roles not appearing in the token** - check that the **User Realm Role** mapper adds to both ID and access tokens. Use **Evaluate** on the client scope in Keycloak to preview the token a specific user would receive.

**Groups not appearing in the token** - verify the **Group Membership** mapper has **Full group path** enabled and is added to ID token, access token, and userinfo.

**`jwks keys not found`** - confirm the Server URL is reachable from Bifrost. The JWKS endpoint is `{serverUrl}/realms/{realm}/protocol/openid-connect/certs`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.