# Set Up ACP with Microsoft Entra ID

Step-by-step guide to configuring Microsoft Entra ID (Azure AD) as your identity provider for ACP. Map app roles, scp claims, and tenant IDs.

# Set Up ACP with Microsoft Entra ID

Microsoft Entra ID (formerly Azure AD) is the identity provider for organizations on Microsoft 365. This guide walks you through configuring Entra ID to issue JWTs that ACP can verify and enforce — so every tool call from your AI agents carries the user's real identity.

---

## What you need

- A Microsoft Entra ID tenant (any tier — Free works)
- An ACP Cloud workspace ([sign up](https://cloud.agenticcontrolplane.com/login?from=%2Fonboarding))

---

## Step 1: Register an application

In the Azure portal, go to **Microsoft Entra ID → App registrations → New registration**.

| Field | Value |
|-------|-------|
| Name | `ACP Gateway` |
| Supported account types | Accounts in this organizational directory only |
| Redirect URI | `https://api.agenticcontrolplane.com/oauth/callback/entra` |

After registration, note the **Application (client) ID** and **Directory (tenant) ID**.

---

## Step 2: Expose an API

Go to your app's **Expose an API** section:

1. Set the **Application ID URI** to `api://your-client-id` (or a custom URI like `https://api.agenticcontrolplane.com/your-slug`)
2. Add scopes:

| Scope | Admin consent display name | Who can consent |
|-------|---------------------------|-----------------|
| `salesforce.read` | Read Salesforce data | Admins and users |
| `salesforce.write` | Write Salesforce data | Admins only |
| `github.read` | Read GitHub data | Admins and users |
| `github.write` | Write GitHub data | Admins only |

---

## Step 3: Define app roles

Go to **App roles → Create app role**:

| Display name | Value | Allowed member types |
|-------------|-------|---------------------|
| Sales Read Only | `Sales.Read` | Users/Groups |
| Sales Full Access | `Sales.ReadWrite` | Users/Groups |
| Developer | `Developer` | Users/Groups |
| Admin | `Admin` | Users/Groups |

Then go to **Enterprise applications → your app → Users and groups** to assign users and groups to roles.

App roles appear in the `roles` claim of Entra ID JWTs.

---

## Step 4: Configure token claims

Go to **Token configuration → Add optional claim**:

1. Token type: **Access token**
2. Add these claims:
   - `email` — user's email address
   - `preferred_username` — user's UPN
   - `groups` — group memberships (if you prefer groups over app roles)

For groups: if you have many groups, Entra ID returns a groups overage claim with a Graph API URL instead. App roles don't have this limitation — prefer app roles for production.

---

## Step 5: Configure ACP

In your ACP dashboard, go to **Settings → Identity Providers** and enter:

| Field | Value |
|-------|-------|
| Issuer | `https://login.microsoftonline.com/{tenant-id}/v2.0` |
| Audience | `api://your-client-id` |
| JWKS URI | Leave blank (auto-discovered from issuer) |
| Scope Claim | `scp` |
| Role Claim | `roles` |
| Tenant Claim | `tid` |

### Entra ID claim mapping

| Entra ID Claim | ACP Field | Example |
|----------------|-----------|---------|
| `sub` | `identity.sub` | `AAAAAAAAABBBBBBcccc123` |
| `iss` | `identity.issuer` | `https://login.microsoftonline.com/{tid}/v2.0` |
| `scp` | `identity.scopes` | `["salesforce.read", "github.read"]` |
| `roles` | `identity.roles` | `["Sales.Read", "Developer"]` |
| `tid` | `identity.tenantId` | `72f988bf-86f1-41af-91ab-2d7cd011db47` |
| `email` | `identity.email` | `alice@contoso.com` |
| `name` | `identity.name` | `Alice Chen` |

Entra ID uses `scp` for delegated permissions (user consented) and `roles` for application roles (admin assigned). ACP checks both.

---

## Step 6: Configure tool scopes

In **Policies → Tool Scopes**, map permissions to tools:

```json
{
  "salesforce.query": ["salesforce.read"],
  "salesforce.createRecord": ["salesforce.write"],
  "github.listRepos": ["github.read"],
  "github.createIssue": ["github.write"]
}
```

---

## Multi-tenant Entra ID

Entra ID includes a `tid` (tenant ID) claim in every JWT. Set the **Tenant Claim** to `tid` in ACP's IdP config.

ACP uses this for tenant isolation automatically. Users from `contoso.com` can't access `fabrikam.com`'s data, even if both organizations use ACP.

If you set "Supported account types" to "Accounts in any organizational directory" during app registration, you can onboard multiple Entra ID tenants to a single ACP workspace. Each tenant's users are isolated by their `tid` claim.

---

## Troubleshooting

**"Invalid token: unexpected iss claim"**
Entra ID v2.0 tokens use `https://login.microsoftonline.com/{tenant-id}/v2.0` as the issuer. V1.0 tokens use `https://sts.windows.net/{tenant-id}/`. Make sure your ACP issuer config matches the token version your app is configured to use.

**"Insufficient scope"**
Check: (1) the scope is defined in "Expose an API," (2) the user or admin has consented to the scope, (3) the client is requesting the scope during auth. For admin-only scopes, a tenant admin must grant consent.

**"roles claim missing"**
App roles must be assigned to users or groups in the Enterprise Application blade. If a user has no role assignments, the `roles` claim won't appear in their token.

**"groups claim returns a URL instead of groups"**
You've hit the groups overage limit (~200 groups). Switch to app roles, or use the Graph API URL returned in the `_claim_sources` to fetch groups. App roles don't have this limitation.

---

[Back to guides](/guides/) · [Set up Okta →](/guides/okta/) · [Set up Auth0 →](/guides/auth0/)
