> For the complete documentation index, see [llms.txt](https://docs.coherent.global/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.coherent.global/identity-and-access-management/client-credentials/ms-entra-id-managed-identity-for-client-credentials.md).

# MS Entra ID managed identity for client credentials

## Prerequisites

<details>

<summary>Permissions required for registering and configuring an app in Microsoft Entra ID.</summary>

The account must have permission to manage applications in Microsoft Entra ID. Ideally the account should be in the Global Admin role to grant admin consent.

</details>

<details>

<summary>Keycloak and Microsoft Entra ID configurations.</summary>

* [Microsoft Entra ID (OIDC)](/identity-and-access-management/single-sign-on/microsoft-entra-id-oidc.md) implemented.
* [Microsoft Entra User-Assigned Managed Identity (UAMI)](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) implemented.
* In Keycloak, the administrator requires the following permissions: `manage-identity-providers`, `view-identity-providers`, `view-authorization`, `manage-authorization`, `view-clients`, and `manage-clients`.

</details>

This article provides the minimum technical detail required to implement the solution. Detailed step-by-step guidance can be generated by an AI client from this content when needed.

## Managed identity for Azure workloads

For Azure workloads, Microsoft Entra User-Assigned Managed Identity (UAMI) can replace a long-lived Keycloak client secret or certificate.

<table><thead><tr><th valign="top">Feature</th><th valign="top">Client secret</th><th valign="top">Certificate</th><th valign="top">Managed identity</th></tr></thead><tbody><tr><td valign="top">Credential stored by workload</td><td valign="top">Yes</td><td valign="top">Private key</td><td valign="top">No</td></tr><tr><td valign="top">Rotation required</td><td valign="top">Yes</td><td valign="top">Yes</td><td valign="top">No application credential</td></tr><tr><td valign="top">Expiration management</td><td valign="top">Yes</td><td valign="top">Yes</td><td valign="top">No</td></tr><tr><td valign="top">Azure workload overhead</td><td valign="top">Medium</td><td valign="top">Medium</td><td valign="top">Low</td></tr></tbody></table>

Where managed identity is suitable, remove the application-managed credential and therefore remove its rotation process.

```mermaid
flowchart LR
    A[Azure workload]
    B[Microsoft Entra ID]
    C[Keycloak]
    D[Keycloak access token]
    A -->|uses UAMI| B
    B -->|issues signed JWT| C
    C -->|validates JWT as client assertion| D
```

The steps below cover only the additional integration configuration.

## Implement managed identity for client credentials

It is recommended to use two separate browser tabs for the Azure (A) and Keycloak (K) portals to make it easier to apply the settings.

1. Configure the Entra appliance audience.
   1. (A) In the first tab, sign in to the [Azure Portal](https://portal.azure.com/).
   2. (A) Search for **Microsoft Entra ID**. Expand **Manage** in the left pane and click **App registrations**.
   3. (A) Navigate to the application created in [Microsoft Entra ID (OIDC)](/identity-and-access-management/single-sign-on/microsoft-entra-id-oidc.md).
   4. (A) Configure **Application ID URI** to `api://{ENTRA-APPLICATION-CLIENT-ID}` .
   5. (A) Configure the application manifest. This defines the audience requested by the managed identity and uses the Entra v2 token issuer expected by the Keycloak trust.

      ```
      "requestedAccessTokenVersion": 2 
      ```
2. Create and assign application role.
   1. (A) Navigate to the application created in [Microsoft Entra ID (OIDC)](/identity-and-access-management/single-sign-on/microsoft-entra-id-oidc.md).
   2. (A) Select **Create app role***.*
   3. (A) Provide the following values then select **Apply**.

      | Key                      | Value                   |
      | ------------------------ | ----------------------- |
      | **Display name**         | `Keycloak Authenticate` |
      | **Allowed member types** | `Applications`          |
      | **Value**                | `Keycloak.Authenticate` |
      | **Enabled**              | `Yes`                   |
   4. (A) Assign this role to the UAMI with this PowerShell script. This explicitly authorizes the managed identity for the Keycloak authentication integration. The Entra token should contain `roles = ["Keycloak.Authenticate"]`. Managed Identity tokens are cached, so a new role assignment may not appear immediately.

      ```powershell
      Connect-MgGraph -Scopes "Application.Read.All","AppRoleAssignment.ReadWrite.All"
      $managedIdentityObjectId = "{UAMI-OBJECT-ID}"
      $resourceAppClientId = "{ENTRA-APPLICATION-CLIENT-ID}"
      $appRoleValue = "Keycloak.Authenticate"
      $resourceServicePrincipal = Get-MgServicePrincipal -Filter "appId eq '$resourceAppClientId'"
      $appRole = $resourceServicePrincipal.AppRoles | Where-Object { $_.Value -eq $appRoleValue -and $_.AllowedMemberTypes -contains "Application" -and $_.IsEnabled }
      $params = @{ PrincipalId = $managedIdentityObjectId; ResourceId = $resourceServicePrincipal.Id; AppRoleId = $appRole.Id }
      New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $managedIdentityObjectId -BodyParameter $params
      ```
3. **Enable Signed JWT - Federated** in Keycloak. This makes the federated JWT authenticator available to Keycloak clients.
   1. (K) Open a new tab in your browser and sign in to the target Spark tenant. Access the **Keycloak console** from the [Navigation menu](/navigation/navigation-menu.md#user-menu).
   2. (K) Navigate to **Authentication** and the Clients authentication flow.
   3. (K) Enable **Signed JWT - Federated**.
4. Update the existing Entra OIDC identity provider.
   1. (A) Navigate to the application created in [Microsoft Entra ID (OIDC)](/identity-and-access-management/single-sign-on/microsoft-entra-id-oidc.md).
   2. (A) Update the following settings.

      | Key                                             | Value |
      | ----------------------------------------------- | ----- |
      | **Supports client assertions**                  | `ON`  |
      | **Allows client assertions to be re-used**      | `ON`  |
      | **Allows Client ID as audience for assertions** | `ON`  |
   3. (A) **Signature validation** and the **Entra JWKS URL** must also be configured so Keycloak can validate Entra-signed assertions.
5. Configure the Keycloak client.
   1. (K) Navigate to the client created in [Microsoft Entra ID (OIDC)](/identity-and-access-management/single-sign-on/microsoft-entra-id-oidc.md).
   2. (K) Under credentials configure:

      | Key                                             | Value                    |
      | ----------------------------------------------- | ------------------------ |
      | **Client Authenticator**                        | `Signed JWT - Federated` |
      | **Identity provider**                           | `{ENTRA-IDP-ALIAS}`      |
      | **Allows Client ID as audience for assertions** | `{UAMI-OBJECT-ID}`       |
   3. The federated subject maps the Entra managed identity to the Keycloak client.
      * **UAMI Client ID** used by `Azure.Identity` (`ManagedIdentityClientId`)
      * **UAMI Object ID** used for role assignment and Keycloak Federated subject.
6. Obtain the Entra token.
   1. Use this C# code snippet to retrieve the Entra token.

      ```csharp
      using Azure.Core;
      using Azure.Identity;

      var credential = new DefaultAzureCredential(
          new DefaultAzureCredentialOptions
          {
              ManagedIdentityClientId = "<UAMI-CLIENT-ID>"
          });

      AccessToken token = await credential.GetTokenAsync(
          new TokenRequestContext(
          [
              "api://<ENTRA-APPLICATION-CLIENT-ID>/.default"
          ]));

      string entraAccessToken = token.Token;
      ```
   2. Verify the token contains the expected issuer (`iss`), audience (`aud`), managed identity subject (`sub`), and `Keycloak.Authenticate` role.
7. Exchange the Entra token for a Keycloak token.
   1. Keycloak validates the Entra JWT as the client assertion and returns the normal Keycloak access token.

      ```shellscript
      curl --location 'https://keycloak.{environment}.coherent.global/auth/realms/{tenant}/protocol/openid-connect/token' \
      --header 'Content-Type: application/x-www-form-urlencoded' \
      --data-urlencode 'grant_type=client_credentials' \
      --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
      --data-urlencode 'client_assertion={ENTRA-MANAGED-IDENTITY-TOKEN}'
      ```
