返回 Skills 目录
microsoft/azure-skills包含需要注意的行为

SKILL DETAIL

entra-agent-id

microsoft/azure-skills/entra-agent-id

此技能用于通过 Microsoft Graph 创建和管理 AI 代理的 OAuth 2.0 身份。每个代理实例获得独特的身份、审计跟踪和独立范围的权限授予。 概念模型包括:Agent Identity Blueprint(应用程序)→ BlueprintPrincipal(服务主体)→ Agent Identity(服务主体)。Blueprint 定义代理类型并持有凭据(机密、证书、联合身份)。BlueprintPrincipal 必须显式创建。Agent Identity 是单个代理实例的服务主体,不能持有自己的凭据。 运行时身份验证使用 Blueprint 上配置的凭据,支持托管身份 + 工作负载身份联合(生产)、客户端机密(本地开发)或 Microsoft Entra SDK for AgentID 边车(多语言代理)。实现两步 fmi_path 令牌交换(自主或 OBO)以获取每个代理实例的独特 sub 声明。支持跨租户令牌流。 权限授予按代理身份进行,支持应用程序权限(自主)和委派权限(OBO)。使用 oauth2PermissionGrants 进行程序化委派同意。 此技能指导直接调用 Microsoft Graph API(PowerShell 或 Python requests),并使用 mcp_azure_mcp_documentation 工具验证请求体和端点。

安装量 · 1,505查看来源

Installation

npx skills add https://github.com/microsoft/azure-skills --skill entra-agent-id

技能文件

SKILL.md

最近同步 · 2026年10月22日

references/known-limitations.md›
# Known Limitations

Source: [Microsoft Entra Agent ID — known issues and gaps](https://learn.microsoft.com/en-us/entra/agent-id/identity-platform/preview-known-issues)

## API & Object Model

1. **Sponsors must be Users at Blueprint creation** — ServicePrincipals and Groups are not accepted as Blueprint sponsors. (Agent Identity sponsors may be Users or Groups.)
2. **BlueprintPrincipal not auto-created** — requires explicit `POST /servicePrincipals/microsoft.graph.agentIdentityBlueprintPrincipal` after Blueprint creation.
3. **Agent Identities cannot have password credentials** — credentials belong on the Blueprint only (`PropertyNotCompatibleWithAgentIdentity`).
4. **Agent Identities have no backing application object** — they are service-principal-only entities.
5. **Blueprint needs explicit `identifierUris`** — not set by default; required for OAuth2 scope resolution (`api://{app-id}/.default`).
6. **No Graph relationship filtering for Agent IDs** — `/ownedObjects`, `/deletedItems`, `/owners` return all types; filter client-side by `odata.type`.
7. **Orphaned agent users after deletion** — deleting a Blueprint or identity does NOT auto-delete its agent users; clean up manually via admin center or Graph API.

## Roles & Permissions

8. **`Directory.AccessAsUser.All` hard rejection** — if present on the client, all other Agent ID delegated permissions are ignored → 403 Forbidden.
9. **No viable delegated permission for creating Agent Identities** — use application permissions.
10. **No quick-start permission bundle** — discover and grant 18+ individual Agent Identity permissions.
11. **Permission propagation delay** — 30–120+ seconds after admin consent before tokens include new claims; prefer delegated permissions and add exponential backoff retry.
12. **Global Reader cannot list Agent Identities** — `GET /servicePrincipals/microsoft.graph.agentIdentity` returns 403; use `GET /servicePrincipals` and filter instead.
13. **Custom roles cannot include Agent ID actions** — use built-in roles (Agent ID Administrator, Agent ID Developer).
14. **Administrative units not supported** — cannot add Agent Identities, Blueprints, or BlueprintPrincipals to admin units; use `owners` instead.
15. **Agent ID Admin cannot update agent-user photos** — use User Administrator.

## Admin Center & Management

16. **No Blueprint management in Entra admin center** — use Microsoft Graph / PowerShell.
17. **`/me` endpoint unavailable** in `client_credentials` flow — use `az ad signed-in-user show` or Graph delegated permissions for user context.

## Authentication & Consent

18. **No SSO to web apps** — Agent IDs can't sign in via Entra ID sign-in pages (no OpenID Connect or SAML); use web APIs instead.
19. **Admin consent workflow (ACW) broken** for permissions requested by Agent IDs — contact tenant admin directly.
20. **Cannot grant app permissions to BlueprintPrincipals** — grant to individual Agent Identities.
21. **Cannot assign app roles where target resource is an Agent Identity** — use the BlueprintPrincipal as target resource.
22. **Risk-based step-up blocks consent silently** — no "risky" indication in the UX.

## Groups, Logs & Monitoring

23. **No dynamic group membership** — Agent Identities and agent users cannot be added to dynamic groups; use security groups with fixed membership.
24. **Audit logs do not distinguish Agent IDs** — operations on Blueprints/identities logged as `ApplicationManagement`, agent users as `User Management`; cross-reference object IDs via Graph to determine entity type.
25. **Graph activity logs do not distinguish Agent IDs** — agent-identity requests logged as applications, agent-user requests as users; join with sign-in logs.

## Performance & Scale

26. **Sequential creation requests may fail** — Blueprint → Principal → Identity in quick succession can return `400 Bad Request: Object with id {id} not found`, especially with application permissions. Prefer delegated permissions; add exponential backoff.

## Product Integrations

27. **Copilot Studio** — only custom engine agents are supported; Agent IDs are used for channel auth only (not connectors or tools).
28. **MSAL complexity** — Agent ID scenarios require managing Federated Identity Credentials manually. For .NET use [Microsoft.Identity.Web.AgentIdentities](https://github.com/AzureAD/microsoft-identity-web/blob/master/src/Microsoft.Identity.Web.AgentIdentities/README.AgentIdentities.md). For other languages use the [Microsoft Entra SDK for AgentID](https://learn.microsoft.com/en-us/entra/msidweb/agent-id-sdk/overview).

## Reporting Issues

Report unlisted issues via [aka.ms/agentidfeedback](https://aka.ms/agentidfeedback).
references/oauth2-token-flow.md›
# OAuth2 Token Flow

Source: [Agent ID Setup Instructions](https://learn.microsoft.com/en-us/entra/agent-id/identity-platform/agent-id-setup-instructions)

Agent Identities authenticate at runtime using credentials configured on the **Blueprint** (not on the Agent Identity — Agent Identities cannot hold credentials).

| Option | Use case | Credential type |
|--------|----------|-----------------|
| **Managed Identity + WIF** | Production (Azure-hosted) | Federated Identity Credential on Blueprint |
| **Client secret** | Local dev / testing | Password credential on Blueprint |

Both options feed the two-step `fmi_path` exchange in [runtime-token-exchange.md](runtime-token-exchange.md).

---

## Option A: Managed Identity + Workload Identity Federation (Production)

### 1. Set the Application ID URI on the Blueprint

```python
requests.patch(
    f"{GRAPH}/applications/{blueprint_obj_id}",
    headers=headers,
    json={"identifierUris": [f"api://{blueprint_app_id}"]},
).raise_for_status()
```

### 2. Create a Federated Identity Credential on the Blueprint

Use the typed path — FICs go on the Blueprint, not on the Agent Identity SP:

```python
fic_body = {
    "name": "my-fic-name",
    "issuer": f"https://login.microsoftonline.com/{tenant_id}/v2.0",
    "subject": mi_principal_id,   # The MI's object ID (principalId), NOT client ID
    "audiences": ["api://AzureADTokenExchange"],
}
requests.post(
    f"{GRAPH}/applications/{blueprint_obj_id}"
    f"/microsoft.graph.agentIdentityBlueprint/federatedIdentityCredentials",
    headers=headers, json=fic_body,
).raise_for_status()
```

### 3. Acquire a token from the caller

```python
from azure.identity import ManagedIdentityCredential

cred = ManagedIdentityCredential(client_id=MI_CLIENT_ID)
token = cred.get_token(f"api://{blueprint_app_id}/.default")
# Authorization: Bearer {token.token}
```

### 4. Validate on the backend

```python
import jwt
from jwt import PyJWKClient

jwks_client = PyJWKClient(
    f"https://login.microsoftonline.com/{tenant_id}/discovery/v2.0/keys"
)
signing_key = jwks_client.get_signing_key_from_jwt(token_str)

claims = jwt.decode(
    token_str,
    signing_key.key,
    algorithms=["RS256"],
    audience=f"api://{blueprint_app_id}",
    issuer=f"https://sts.windows.net/{tenant_id}/",
)
```

### Key Rules (WIF)

- **FICs go on the Blueprint** using the typed path (`.../microsoft.graph.agentIdentityBlueprint/federatedIdentityCredentials`).
- **`subject`** is the MI's `principalId` (object ID), not its client ID.
- **`audiences`** must be `["api://AzureADTokenExchange"]` — not your API audience.
- **FIC `issuer`**: `https://login.microsoftonline.com/{tenant}/v2.0`.
- **Token `issuer`** for validation: `https://sts.windows.net/{tenant}/` (different domain, trailing slash).

---

## Option B: Client Secret (Local Dev)

### 1. Add a password credential to the Blueprint

PowerShell:

```powershell
$body = @{
    "passwordCredential" = @{
        "displayName" = "Dev Secret"
        "endDateTime" = "2027-01-01T00:00:00Z"
    }
}

$credential = Invoke-MgGraphRequest -Method POST `
    -Uri "https://graph.microsoft.com/v1.0/applications/<BLUEPRINT_OBJECT_ID>/addPassword" `
    -Headers @{ "OData-Version" = "4.0"; "Content-Type" = "application/json" } `
    -Body ($body | ConvertTo-Json -Depth 5) -OutputType PSObject

$credential.secretText   # Save NOW — not retrievable later
```

Python:

```python
resp = requests.post(
    f"{GRAPH}/applications/{blueprint_obj_id}/addPassword",
    headers=headers,
    json={"passwordCredential": {
        "displayName": "Dev Secret",
        "endDateTime": "2027-01-01T00:00:00Z",
    }},
)
resp.raise_for_status()
secret_text = resp.json()["secretText"]   # Save NOW
```

### 2. Drive the two-step exchange

Pass `blueprint_secret=secret_text` into `get_parent_token(...)` from
[runtime-token-exchange.md](runtime-token-exchange.md), then call `exchange_autonomous` or `exchange_obo`.

### Key Rules (Client Secret)

- **Save `secretText` immediately** — it can't be retrieved later.
- **Secrets belong on the Blueprint only** — Agent Identities can't have password credentials (`PropertyNotCompatibleWithAgentIdentity`).
- **Not for production** — use MI + WIF.
- **Respect org credential-lifetime policy** when setting `endDateTime`.
- Don't use `DefaultAzureCredential` to acquire Blueprint tokens — Azure CLI tokens carry `Directory.AccessAsUser.All` and are rejected. Use `ClientSecretCredential` or the raw HTTP exchange.
references/obo-blueprint-setup.md›
# OBO Blueprint Setup

To use **OBO (on-behalf-of)** mode — where an agent acts on behalf of a user — the Blueprint must be configured as an OAuth2 API so the user's token can target it as audience.

## Configure the Blueprint as an API

Apply once via `PATCH /applications/{blueprint_obj_id}`:

```python
import uuid

scope_id = str(uuid.uuid4())
patch = {
    "identifierUris": [f"api://{blueprint_app_id}"],
    "api": {
        "requestedAccessTokenVersion": 2,
        "oauth2PermissionScopes": [{
            "id": scope_id,
            "adminConsentDescription": "Allow the app to access the agent API on behalf of the user.",
            "adminConsentDisplayName": "Access agent API",
            "userConsentDescription": "Allow the app to access the agent API on your behalf.",
            "userConsentDisplayName": "Access agent API",
            "value": "access_as_user",
            "type": "User",
            "isEnabled": True,
        }],
        "preAuthorizedApplications": [{
            "appId": client_app_id,   # Your front-end or CLI app's appId
            "permissionIds": [scope_id],
        }],
    },
    "optionalClaims": {
        "accessToken": [{
            "name": "idtyp",
            "source": None,
            "essential": False,
            "additionalProperties": ["include_user_token"],
        }]
    },
}
requests.patch(
    f"{GRAPH}/applications/{blueprint_obj_id}",
    headers=headers, json=patch,
).raise_for_status()
```

All four pieces are required:

1. **`identifierUris`** — enables `api://{appId}` as audience.
2. **`oauth2PermissionScopes`** — defines the `access_as_user` scope users can consent to.
3. **`preAuthorizedApplications`** — authorizes your client app and skips the consent prompt.
4. **`optionalClaims`** — emits the `idtyp` claim needed for token-type validation.

## Grant Delegated Permissions to Each Agent Identity

Each Agent Identity needs `oauth2PermissionGrants` specifying which Graph delegated permissions it may exercise on behalf of users:

```python
from datetime import datetime, timedelta, timezone

expiry = (datetime.now(timezone.utc) + timedelta(days=3650)).strftime("%Y-%m-%dT%H:%M:%SZ")

requests.post(
    f"{GRAPH}/oauth2PermissionGrants",
    headers=headers,
    json={
        "clientId": agent_sp_id,     # Agent Identity SP object ID
        "consentType": "AllPrincipals",
        "resourceId": graph_sp_id,   # Microsoft Graph SP object ID
        "scope": "User.Read Tasks.ReadWrite",
        "expiryTime": expiry,
    },
).raise_for_status()
```

## Acquire the User Token — Targeting the Blueprint

```python
from azure.identity import InteractiveBrowserCredential

credential = InteractiveBrowserCredential(
    tenant_id=tenant_id,
    client_id=client_app_id,   # Your client app, NOT the Blueprint
    redirect_uri="http://localhost:8400",
)
user_token = credential.get_token(f"api://{blueprint_app_id}/access_as_user")
```

> If the user token targets `https://graph.microsoft.com` instead of the Blueprint, the OBO exchange returns `AADSTS50013: Assertion failed signature validation`.

Then feed `user_token.token` into `exchange_obo(...)` from [runtime-token-exchange.md](runtime-token-exchange.md).

## Per-Agent Scoping

Different agents can have different permission boundaries:

```python
AGENT_SCOPES = {
    "it-helpdesk":   "User.Read Tasks.ReadWrite",
    "comms-agent":   "User.Read Mail.Send Calendars.ReadWrite",
    "hr-onboarding": "User.Read User.ReadBasic.All",
}

for agent_name, scopes in AGENT_SCOPES.items():
    grant_delegated(agent_identities[agent_name], scopes)
```

## Key Rules (OBO)

- **User token audience = Blueprint** (`api://{blueprint_app_id}/access_as_user`), not Graph.
- **Use `/.default` scope** on the OBO exchange step.
- **`expiryTime` is required** on `oauth2PermissionGrants` for Agent Identity grants.
- **Browser-based admin consent URLs do not work** for Agent Identities — use `oauth2PermissionGrants` API for programmatic consent.
- **`Group.ReadWrite.All`** cannot be granted as a delegated permission to Agent Identities. `Tasks.ReadWrite` alone covers Planner task operations.
- Not every Graph scope is allowed for Agent Identities — test each new scope.
references/runtime-token-exchange.md›
# Runtime Token Exchange (`fmi_path`)

Source: [Agent ID Setup Instructions](https://learn.microsoft.com/en-us/entra/agent-id/identity-platform/agent-id-setup-instructions)

Agent Identities authenticate at runtime via a **two-step token exchange** against the Entra `/oauth2/v2.0/token` endpoint. This is a standard Entra feature — it works anywhere (Azure, on-premises, local dev), not only inside Foundry.

```
Step 1: Blueprint credentials + fmi_path  →  Parent token (aud: api://AzureADTokenExchange)
Step 2: Parent token as client_assertion  →  Graph token (aud: https://graph.microsoft.com)
```

The `fmi_path` parameter targets a specific Agent Identity, so the resulting Graph token has `sub = <that Agent Identity's appId>` — giving each agent instance a distinct audit trail.

## Step 1: Get the parent token

```python
import json, urllib.parse, urllib.request

TOKEN_URL = "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token"

def get_parent_token(tenant_id: str, blueprint_app_id: str,
                     blueprint_secret: str, agent_identity_app_id: str) -> str:
    """Parent token scoped to a specific Agent Identity.

    tenant_id: the Agent Identity's home tenant (NOT the Blueprint's home
               tenant, if cross-tenant).
    """
    params = {
        "grant_type": "client_credentials",
        "client_id": blueprint_app_id,
        "client_secret": blueprint_secret,
        "scope": "api://AzureADTokenExchange/.default",
        "fmi_path": agent_identity_app_id,
    }
    data = urllib.parse.urlencode(params).encode("utf-8")
    req = urllib.request.Request(
        TOKEN_URL.format(tenant=tenant_id), data=data,
        headers={"Content-Type": "application/x-www-form-urlencoded"},
    )
    with urllib.request.urlopen(req, timeout=10) as resp:
        return json.loads(resp.read())["access_token"]
```

The parent token carries:

| Claim | Value |
|-------|-------|
| `aud` | `api://AzureADTokenExchange` |
| `iss` | `https://login.microsoftonline.com/{tenant}/v2.0` |
| `sub` | Blueprint SP object ID |
| `appid` | Blueprint appId |
| `idtyp` | `app` |

This token cannot call Graph directly — it's an intermediate used as `client_assertion` in step 2.

### Using MI + WIF for step 1

Replace `client_secret` with a federated assertion from a Managed Identity. The MI first acquires a token for `api://AzureADTokenExchange`, then presents it as `client_assertion`:

```python
from azure.identity import ManagedIdentityCredential

mi = ManagedIdentityCredential(client_id=MI_CLIENT_ID)
mi_token = mi.get_token("api://AzureADTokenExchange/.default").token

params = {
    "grant_type": "client_credentials",
    "client_id": BLUEPRINT_APP_ID,
    "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
    "client_assertion": mi_token,
    "scope": "api://AzureADTokenExchange/.default",
    "fmi_path": AGENT_IDENTITY_APP_ID,
}
```

Set up the FIC on the Blueprint first — see [oauth2-token-flow.md](oauth2-token-flow.md).

## Step 2a: Autonomous exchange (app-only permissions)

```python
def exchange_autonomous(tenant_id: str, agent_identity_app_id: str,
                        parent_token: str) -> dict:
    params = {
        "grant_type": "client_credentials",
        "client_id": agent_identity_app_id,
        "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_assertion": parent_token,
        "scope": "https://graph.microsoft.com/.default",
    }
    data = urllib.parse.urlencode(params).encode("utf-8")
    req = urllib.request.Request(
        TOKEN_URL.format(tenant=tenant_id), data=data,
        headers={"Content-Type": "application/x-www-form-urlencoded"},
    )
    with urllib.request.urlopen(req, timeout=10) as resp:
        return json.loads(resp.read())
```

Resulting token has `sub = agent_identity_app_id` and `roles = <application permissions granted via appRoleAssignments>`.

## Step 2b: OBO exchange (delegated permissions)

Combines the parent token with a user token to produce a delegated Graph token scoped to whatever the Agent Identity is allowed to do on behalf of the user.

Prerequisites: the Blueprint must be configured as an OAuth2 API ([obo-blueprint-setup.md](obo-blueprint-setup.md)) and the Agent Identity must have `oauth2PermissionGrants` for the desired scopes.

```python
def exchange_obo(tenant_id: str, agent_identity_app_id: str,
                 parent_token: str, user_token: str) -> dict:
    params = {
        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "client_id": agent_identity_app_id,
        "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_assertion": parent_token,
        "assertion": user_token,
        "requested_token_use": "on_behalf_of",
        "scope": "https://graph.microsoft.com/.default",
    }
    data = urllib.parse.urlencode(params).encode("utf-8")
    req = urllib.request.Request(
        TOKEN_URL.format(tenant=tenant_id), data=data,
        headers={"Content-Type": "application/x-www-form-urlencoded"},
    )
    with urllib.request.urlopen(req, timeout=10) as resp:
        return json.loads(resp.read())
```

Resulting token has `sub = agent_identity_app_id` and `scp = <delegated scopes granted via oauth2PermissionGrants>`.

The user token MUST target the Blueprint as its audience (`api://{blueprint_app_id}/access_as_user`). If it targets Graph, step 2b returns `AADSTS50013: Assertion failed signature validation`.

## Cross-Tenant Exchange

Blueprints can be multi-tenant (`signInAudience: AzureADMultipleOrgs`). BlueprintPrincipal + Agent Identity exist in the target tenant.

> **Step 1 MUST target the Agent Identity's home tenant.** Wrong tenant ⇒ `AADSTS700211: No matching federated identity record found`.

```python
# Blueprint in Tenant A, Agent Identity in Tenant B.

# CORRECT — step 1 targets Tenant B
parent = get_parent_token(
    tenant_id=TENANT_B,
    blueprint_app_id=BLUEPRINT_APP_ID,
    blueprint_secret=SECRET,
    agent_identity_app_id=AGENT_APP_ID,
)

# WRONG — step 1 targets Tenant A (Blueprint's tenant)
# Parent token issuer won't match FIC; step 2 → AADSTS700211
```

Step 2 also targets Tenant B, using the correctly-issued parent token.

## Key Rules

- Use `/.default` scope in **both** steps. Individual scopes like `User.Read Mail.Send` fail.
- Use `client_credentials` with `fmi_path` — do NOT use `urn:ietf:params:oauth:grant-type:token-exchange` (returns `AADSTS82001`).
- `fmi_path` is the Agent Identity's **appId**, not its SP object ID.
- Autonomous and OBO flows share step 1; only step 2's grant type differs.
- Cross-tenant: step 1 tenant = Agent Identity's home tenant.
references/sdk-sidecar-deployment.md›
# SDK Sidecar — Code Patterns, Deployment, and Security

Companion to [sdk-sidecar.md](sdk-sidecar.md). This file covers calling-side code patterns in Python and TypeScript, container deployment manifests, security hardening, and troubleshooting.

## Code Patterns

### Autonomous 3P Agent (Python)

```python
import os
import requests

SIDECAR_URL = os.environ.get("SIDECAR_URL", "http://localhost:5000")
AGENT_APP_ID = os.environ["AGENT_CLIENT_ID"]

def get_agent_token(downstream_api: str = "Graph") -> str:
    url = f"{SIDECAR_URL}/AuthorizationHeaderUnauthenticated/{downstream_api}"
    resp = requests.get(url, params={"AgentIdentity": AGENT_APP_ID}, timeout=30)
    resp.raise_for_status()
    return resp.json()["authorizationHeader"]

def call_downstream_api(endpoint: str) -> dict:
    token = get_agent_token()
    resp = requests.get(endpoint, headers={"Authorization": token}, timeout=10)
    resp.raise_for_status()
    return resp.json()
```

### Interactive (OBO) Agent (Python)

```python
def get_delegated_token(user_token: str, downstream_api: str = "Graph") -> str:
    url = f"{SIDECAR_URL}/AuthorizationHeader/{downstream_api}"
    resp = requests.get(
        url,
        headers={"Authorization": f"Bearer {user_token}"},
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json()["authorizationHeader"]
```

### Autonomous Agent (TypeScript)

```typescript
const SIDECAR_URL = process.env.SIDECAR_URL ?? "http://localhost:5000";
const AGENT_APP_ID = process.env.AGENT_CLIENT_ID!;

async function getAgentToken(downstreamApi = "Graph"): Promise<string> {
  const url = new URL(
    `/AuthorizationHeaderUnauthenticated/${downstreamApi}`,
    SIDECAR_URL,
  );
  url.searchParams.set("AgentIdentity", AGENT_APP_ID);

  const res = await fetch(url.toString());
  if (!res.ok) {
    const errorText = await res.text().catch(() => "");
    throw new Error(
      `SDK error: ${res.status}${errorText ? ` - ${errorText}` : ""}`,
    );
  }
  const data = await res.json();
  return data.authorizationHeader;
}
```

### Token Validation Middleware

```python
def validate_incoming_token(bearer_token: str) -> dict:
    resp = requests.get(
        f"{SIDECAR_URL}/Validate",
        headers={"Authorization": f"Bearer {bearer_token}"},
        timeout=10,
    )
    resp.raise_for_status()
    return resp.json()["claims"]
```

### Direct Downstream Call via SDK

```python
def call_graph_me(user_token: str) -> dict:
    resp = requests.get(
        f"{SIDECAR_URL}/DownstreamApi/Graph",
        params={"optionsOverride.RelativePath": "me"},
        headers={"Authorization": f"Bearer {user_token}"},
        timeout=10,
    )
    resp.raise_for_status()
    return resp.json()["content"]
```

## Deployment

### Docker Compose (Development)

```yaml
version: '3.8'
services:
  sidecar:
    image: mcr.microsoft.com/entra-sdk/auth-sidecar:1.0.0-azurelinux3.0-distroless
    ports:
      - "5001:5000"
    environment:
      - AzureAd__Instance=https://login.microsoftonline.com/
      - AzureAd__TenantId=${TENANT_ID}
      - AzureAd__ClientId=${BLUEPRINT_APP_ID}
      - AzureAd__ClientCredentials__0__SourceType=ClientSecret
      - AzureAd__ClientCredentials__0__ClientSecret=${BLUEPRINT_CLIENT_SECRET}
      - DownstreamApis__Graph__BaseUrl=https://graph.microsoft.com/v1.0/
      - DownstreamApis__Graph__Scopes__0=https://graph.microsoft.com/.default
      - DownstreamApis__Graph__RequestAppToken=true
      - ASPNETCORE_URLS=http://+:5000

  agent:
    build: ./agent
    ports:
      - "3000:3000"
    environment:
      - SIDECAR_URL=http://sidecar:5000
      - AGENT_CLIENT_ID=${AGENT_CLIENT_ID}
    depends_on:
      - sidecar
```

### Kubernetes (Production)

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: agent-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: agent
        azure.workload.identity/use: "true"
    spec:
      serviceAccountName: agent-sa
      containers:
      - name: agent
        image: myregistry/agent:latest
        env:
        - name: SIDECAR_URL
          value: "http://localhost:5000"
      - name: sidecar
        image: mcr.microsoft.com/entra-sdk/auth-sidecar:1.0.0-azurelinux3.0-distroless
        ports:
        - containerPort: 5000
        env:
        - name: AzureAd__TenantId
          valueFrom:
            configMapKeyRef:
              name: agent-config
              key: tenant-id
        - name: AzureAd__ClientId
          valueFrom:
            configMapKeyRef:
              name: agent-config
              key: client-id
        - name: AzureAd__ClientCredentials__0__SourceType
          value: "SignedAssertionFilePath"
        - name: Kestrel__Endpoints__Http__Url
          value: "http://127.0.0.1:5000"
        resources:
          requests: { memory: "128Mi", cpu: "100m" }
          limits: { memory: "256Mi", cpu: "250m" }
        livenessProbe:
          httpGet: { path: /healthz, port: 5000 }
          initialDelaySeconds: 10
        readinessProbe:
          httpGet: { path: /healthz, port: 5000 }
          initialDelaySeconds: 5
```

## Security

> ⚠️ The SDK API must NOT be publicly accessible. Pod-local or same-Docker-network only.

1. **Bind to localhost** — `Kestrel__Endpoints__Http__Url=http://127.0.0.1:5000`
2. **Never expose via LoadBalancer or Ingress**
3. **Use Workload Identity in AKS** — `SignedAssertionFilePath` over client secrets
4. **Use Key Vault for certificates** — `SourceType=KeyVault` in production
5. **Separate ConfigMap from Secrets** in Kubernetes

## Troubleshooting

| Symptom | Cause | Fix |
|---------|-------|-----|
| 404 on `/AuthorizationHeader/{name}` | `{name}` not in config | Add `DownstreamApis__{name}__BaseUrl` env var |
| 400 `AgentUsername requires AgentIdentity` | Missing `AgentIdentity` param | Always pair user params with `AgentIdentity` |
| 400 `mutually exclusive` | Both `AgentUsername` and `AgentUserId` | Use one or the other |
| 401 on `/Validate` | Invalid/expired inbound token | Check token audience matches `AzureAd__ClientId` |
| 500 token acquisition failure | Wrong creds or missing admin consent | `kubectl logs <pod> -c sidecar` |
| Connection refused | SDK not ready or wrong URL | Verify `SIDECAR_URL` and `/healthz` |
references/sdk-sidecar.md›
# Microsoft Entra SDK for AgentID: Polyglot Agent Authentication

Containerized companion service that handles token management for AI agents over HTTP — any language, any framework.

Image: `mcr.microsoft.com/entra-sdk/auth-sidecar:1.0.0-azurelinux3.0-distroless`. See [GitHub releases](https://github.com/AzureAD/microsoft-identity-web/releases) for tags.

For code patterns, deployment manifests, security hardening, and troubleshooting, see [sdk-sidecar-deployment.md](sdk-sidecar-deployment.md).

## Architecture

```
Client App → Your Agent (Python/Node/Go/Java)
          → Microsoft Entra SDK for AgentID (localhost:5000)
          → Microsoft Entra ID
                                            ↓
                                   Downstream APIs
```

The SDK runs as a companion container in the same pod or Docker network. Your agent calls it over HTTP — no SDK embedding required.

### Agent Integration (3P and Custom Agents)

Third-party and custom agents authenticate using the Blueprint → BlueprintPrincipal → Agent Identity hierarchy. The SDK acquires tokens on their behalf:

```
                                    GET /AuthorizationHeaderUnauthenticated/graph
                                    ?AgentIdentity={agent-app-id}
  ┌──────────────────┐            ┌─────────────────────────────┐
  │  Agent           │ ─────────▶ │  Microsoft Entra SDK for    │
  │  (any language)  │ ◀───────── │  AgentID (:5000)            │
  │                  │  { authorizationHeader: "Bearer eyJ..." }│
  └────────┬─────────┘            └──────────────┬──────────────┘
           │ Authorization: Bearer <JWT>                        │ OAuth 2.0
           ▼                                                    ▼
  ┌──────────────────────┐                      ┌──────────────────────────┐
  │  Downstream APIs     │                      │  Microsoft Entra ID      │
  │  · Microsoft Graph   │                      │  · Blueprint             │
  │  · Custom APIs       │                      │  · AgentIdentity         │
  │  · Azure Services    │                      │                          │
  └──────────────────────┘                      └──────────────────────────┘
```

## SDK Configuration

### Core Settings

```yaml
env:
- name: AzureAd__Instance
  value: "https://login.microsoftonline.com/"
- name: AzureAd__TenantId
  value: "<your-tenant-id>"
- name: AzureAd__ClientId
  value: "<blueprint-app-id>"
```

### Client Credentials

> Client secrets are for development only. Production deployments must use Federated Identity Credentials (FIC) via Workload Identity (`SignedAssertionFilePath`) or Managed Identity.

```yaml
# Dev ONLY — Client Secret
- name: AzureAd__ClientCredentials__0__SourceType
  value: "ClientSecret"
- name: AzureAd__ClientCredentials__0__ClientSecret
  value: "<secret>"

# Prod (AKS) — Federated Identity Credentials via Workload Identity (RECOMMENDED)
- name: AzureAd__ClientCredentials__0__SourceType
  value: "SignedAssertionFilePath"

# Prod (VM / App Service) — Managed Identity
- name: AzureAd__ClientCredentials__0__SourceType
  value: "SignedAssertionFromManagedIdentity"
- name: AzureAd__ClientCredentials__0__ManagedIdentityClientId
  value: "<managed-identity-client-id>"
```

### Downstream API

```yaml
- name: DownstreamApis__Graph__BaseUrl
  value: "https://graph.microsoft.com/v1.0/"
- name: DownstreamApis__Graph__Scopes__0
  value: "https://graph.microsoft.com/.default"
- name: DownstreamApis__Graph__RequestAppToken
  value: "true"
```

## Agent Identity Query Parameters

| Parameter | Purpose | Example |
|-----------|---------|---------|
| `AgentIdentity` | Agent app (client) ID — autonomous mode | `?AgentIdentity=<agent-client-id>` |
| `AgentIdentity` + `AgentUsername` | Interactive mode by UPN | `?AgentIdentity=<id>&[email protected]` |
| `AgentIdentity` + `AgentUserId` | Interactive mode by Object ID | `?AgentIdentity=<id>&AgentUserId=<oid>` |

Rules:
- `AgentUsername`/`AgentUserId` require `AgentIdentity`
- `AgentUsername` and `AgentUserId` are mutually exclusive
- `AgentIdentity` alone = autonomous agent
- `AgentIdentity` + inbound bearer = interactive (OBO) agent

## Endpoint Reference

| Endpoint | Method | Auth Required | Purpose |
|----------|--------|---------------|---------|
| `/Validate` | GET | Yes | Validate inbound bearer, return claims |
| `/AuthorizationHeader/{name}` | GET | Yes | Validate inbound token + acquire downstream token (OBO) |
| `/AuthorizationHeaderUnauthenticated/{name}` | GET | No | Acquire app/agent token without inbound user token |
| `/DownstreamApi/{name}` | ANY | Yes | Validate + call downstream API with auto token |
| `/DownstreamApiUnauthenticated/{name}` | ANY | No | Call downstream API with app/agent token |
| `/healthz` | GET | No | Health probe |

## External Links

| Resource | URL |
|----------|-----|
| SDK Overview | https://learn.microsoft.com/en-us/entra/msidweb/agent-id-sdk/overview |
| Installation | https://learn.microsoft.com/en-us/entra/msidweb/agent-id-sdk/installation |
| Configuration | https://learn.microsoft.com/en-us/entra/msidweb/agent-id-sdk/configuration |
| Endpoints | https://learn.microsoft.com/en-us/entra/msidweb/agent-id-sdk/endpoints |
| Agent Identities | https://learn.microsoft.com/en-us/entra/msidweb/agent-id-sdk/agent-identities |
| Security | https://learn.microsoft.com/en-us/entra/msidweb/agent-id-sdk/security |
| OpenAPI Spec | https://github.com/AzureAD/microsoft-identity-web/blob/master/src/Microsoft.Identity.Web.Sidecar/OpenAPI/Microsoft.Identity.Web.AgentID.json |
SKILL.md›
---
name: entra-agent-id
description: "Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmi_path, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmi_path token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry)."
license: MIT
metadata:
  author: Microsoft
  version: "1.1.1"
---

# Microsoft Entra Agent ID

Create and manage OAuth 2.0-capable identities for AI agents using Microsoft Graph. Every agent instance gets a distinct identity, audit trail, and independently-scoped permission grants.

## Quick Reference

| Property | Value |
|----------|-------|
| Service | Microsoft Entra Agent ID |
| API | Microsoft Graph (`https://graph.microsoft.com/v1.0`) |
| Required role | Agent Identity Developer, Agent Identity Administrator, or Application Administrator |
| Object model | Blueprint (application) → BlueprintPrincipal (SP) → Agent Identity (SP) |
| Runtime exchange | Two-step `fmi_path` exchange (autonomous and OBO) |
| .NET helper | `Microsoft.Identity.Web.AgentIdentities` |
| Polyglot helper | Microsoft Entra SDK for AgentID (sidecar container) |

## When to Use This Skill

- Provisioning a new Agent Identity Blueprint and BlueprintPrincipal
- Creating per-instance Agent Identities under a Blueprint
- Configuring credentials (FIC, Managed Identity, or client secret) on the Blueprint
- Implementing the two-step `fmi_path` runtime token exchange (autonomous or OBO)
- Cross-tenant agent token flows
- Deploying the Microsoft Entra SDK for AgentID sidecar for polyglot agents (Python, Node, Go, Java)
- Granting per-Agent-Identity application (`appRoleAssignments`) or delegated (`oauth2PermissionGrants`) permissions
- Diagnosing Agent ID errors such as `AADSTS82001`, `AADSTS700211`, or `PropertyNotCompatibleWithAgentIdentity`

## MCP Tools

| Tool | Use |
|------|-----|
| `mcp_azure_mcp_documentation` | Search Microsoft Learn for current Agent ID setup, Graph API shapes, and SDK configuration |

There is no dedicated Agent Identity MCP server today. This skill guides direct Microsoft Graph API calls (PowerShell or Python `requests`). Use `mcp_azure_mcp_documentation` to verify request bodies and endpoints against current docs before running.

## Before You Start

Use the `mcp_azure_mcp_documentation` tool to search Microsoft Learn for current Agent ID documentation:
- "Microsoft Entra Agent ID setup instructions"
- "Microsoft Entra SDK for AgentID"

Verify request bodies and endpoints against the installed SDK version — Graph API shapes evolve.

## Conceptual Model

```
Agent Identity Blueprint (application)         ← one per agent type/project
  └── BlueprintPrincipal (service principal)    ← MUST be created explicitly
        ├── Agent Identity (SP): agent-1        ← one per agent instance
        ├── Agent Identity (SP): agent-2
        └── Agent Identity (SP): agent-3
```

| Concept | Description |
|---------|-------------|
| **Blueprint** | Application object that defines a type/class of agent. Holds credentials (secret, certificate, federated identity). |
| **BlueprintPrincipal** | Service principal for the Blueprint in the tenant. Not auto-created. |
| **Agent Identity** | Service-principal-only identity for a single agent instance. Cannot hold its own credentials. |
| **Sponsor** | A User (or Group, for Agent Identity) who is responsible for the identity. Required on creation. |

## Prerequisites

### Required Entra Roles

One of: **Agent Identity Developer**, **Agent Identity Administrator**, or **Application Administrator**.

### PowerShell (interactive setup)

```powershell
# PowerShell 7+
Install-Module Microsoft.Graph.Applications -Scope CurrentUser -Force
```

### Python (programmatic provisioning)

```bash
pip install azure-identity requests
```

## Authentication

> **`DefaultAzureCredential` is not supported.** Azure CLI tokens carry `Directory.AccessAsUser.All`, which Agent Identity APIs hard-reject (403). Use a dedicated app registration with `client_credentials`, or `Connect-MgGraph` with explicit delegated scopes.

### PowerShell (delegated)

```powershell
Connect-MgGraph -Scopes @(
    "AgentIdentityBlueprint.Create",
    "AgentIdentityBlueprint.ReadWrite.All",
    "AgentIdentityBlueprintPrincipal.Create",
    "AgentIdentity.Create.All",
    "User.Read"
)
```

### Python (application)

```python
import os, requests
from azure.identity import ClientSecretCredential

credential = ClientSecretCredential(
    tenant_id=os.environ["AZURE_TENANT_ID"],
    client_id=os.environ["AZURE_CLIENT_ID"],
    client_secret=os.environ["AZURE_CLIENT_SECRET"],
)
token = credential.get_token("https://graph.microsoft.com/.default")

GRAPH = "https://graph.microsoft.com/v1.0"
headers = {
    "Authorization": f"Bearer {token.token}",
    "Content-Type": "application/json",
    "OData-Version": "4.0",
}
```

## Core Workflow

### Step 1: Create Agent Identity Blueprint

Use the typed endpoint. Sponsors must be **Users** at Blueprint creation. This snippet assumes the `requests` client and `headers` dict from the Python authentication block above.

```python
import subprocess
import requests

user_id = subprocess.run(
    ["az", "ad", "signed-in-user", "show", "--query", "id", "-o", "tsv"],
    capture_output=True, text=True, check=True,
).stdout.strip()

blueprint_body = {
    "displayName": "My Agent Blueprint",
    "[email protected]": [
        f"https://graph.microsoft.com/v1.0/users/{user_id}"
    ],
}
resp = requests.post(
    f"{GRAPH}/applications/microsoft.graph.agentIdentityBlueprint",
    headers=headers, json=blueprint_body,
)
resp.raise_for_status()

blueprint = resp.json()
app_id = blueprint["appId"]
blueprint_obj_id = blueprint["id"]
```

### Step 2: Create BlueprintPrincipal

> Mandatory. Creating a Blueprint does NOT auto-create its service principal. Skipping this step produces:
> `400: The Agent Blueprint Principal for the Agent Blueprint does not exist.`

```python
sp_body = {"appId": app_id}
resp = requests.post(
    f"{GRAPH}/servicePrincipals/microsoft.graph.agentIdentityBlueprintPrincipal",
    headers=headers, json=sp_body,
)
resp.raise_for_status()
```

Make your provisioning scripts idempotent — always check for the BlueprintPrincipal even when the Blueprint already exists.

### Step 3: Create Agent Identities

Sponsors for an Agent Identity may be **Users or Groups**.

```python
agent_body = {
    "displayName": "my-agent-instance-1",
    "agentIdentityBlueprintId": app_id,
    "[email protected]": [
        f"https://graph.microsoft.com/v1.0/users/{user_id}"
    ],
}
resp = requests.post(
    f"{GRAPH}/servicePrincipals/microsoft.graph.agentIdentity",
    headers=headers, json=agent_body,
)
resp.raise_for_status()
agent = resp.json()
agent_sp_id = agent["id"]
```

## Runtime Authentication

Agents authenticate at runtime using credentials configured on the **Blueprint** (not on the Agent Identity — Agent Identities can't hold credentials).

| Option | Use case | Credential on Blueprint |
|--------|----------|------------------------|
| **Managed Identity + WIF** | Production (Azure-hosted) | Federated Identity Credential |
| **Client secret** | Local dev / testing | Password credential |
| **Microsoft Entra SDK for AgentID** | Polyglot / 3P agents | Sidecar container acquires tokens over HTTP |

For the two-step `fmi_path` exchange (parent token → per-Agent-Identity Graph token) that gives each agent instance a distinct `sub` claim and audit trail, see [references/runtime-token-exchange.md](references/runtime-token-exchange.md).

For OBO (agent acting on behalf of a user), see [references/obo-blueprint-setup.md](references/obo-blueprint-setup.md).

For the containerized polyglot auth sidecar (Python, Node, Go, Java — no SDK embedding), see [references/sdk-sidecar.md](references/sdk-sidecar.md).

For MI+WIF and client-secret setup details, see [references/oauth2-token-flow.md](references/oauth2-token-flow.md).

### .NET quick path

For .NET services, use **`Microsoft.Identity.Web.AgentIdentities`** — it handles Federated Identity Credential management and the two-step exchange for you. See the package README at `github.com/AzureAD/microsoft-identity-web` under `src/Microsoft.Identity.Web.AgentIdentities/`.

## Granting Permissions (Per Agent Identity)

Agent Identities support both application permissions (autonomous) and delegated permissions (OBO). Grants are scoped **per Agent Identity**, not to the BlueprintPrincipal.

### Application permissions (autonomous)

```python
graph_sp = requests.get(
    f"{GRAPH}/servicePrincipals?$filter=appId eq '00000003-0000-0000-c000-000000000000'",
    headers=headers,
).json()["value"][0]

user_read_all = next(r for r in graph_sp["appRoles"] if r["value"] == "User.Read.All")

requests.post(
    f"{GRAPH}/servicePrincipals/{agent_sp_id}/appRoleAssignments",
    headers=headers,
    json={
        "principalId": agent_sp_id,
        "resourceId": graph_sp["id"],
        "appRoleId": user_read_all["id"],
    },
).raise_for_status()
```

### Delegated permissions (OBO)

```python
from datetime import datetime, timedelta, timezone

expiry = (datetime.now(timezone.utc) + timedelta(days=3650)).strftime("%Y-%m-%dT%H:%M:%SZ")

requests.post(
    f"{GRAPH}/oauth2PermissionGrants",
    headers=headers,
    json={
        "clientId": agent_sp_id,
        "consentType": "AllPrincipals",
        "resourceId": graph_sp["id"],
        "scope": "User.Read Tasks.ReadWrite Mail.Send",
        "expiryTime": expiry,
    },
).raise_for_status()
```

Browser-based admin consent URLs do not work for Agent Identities — use `oauth2PermissionGrants` for programmatic delegated consent.

## Cross-Tenant Agent Identities

Blueprints can be multi-tenant (`signInAudience: AzureADMultipleOrgs`). When exchanging tokens cross-tenant:

> **Step 1 of the parent token exchange MUST target the Agent Identity's home tenant**, not the Blueprint's. Wrong tenant → `AADSTS700211: No matching federated identity record found`.

See [references/runtime-token-exchange.md](references/runtime-token-exchange.md) for full cross-tenant examples.

## API Reference

| Operation | Method | Endpoint |
|-----------|--------|----------|
| Create Blueprint | `POST` | `/applications/microsoft.graph.agentIdentityBlueprint` |
| Create BlueprintPrincipal | `POST` | `/servicePrincipals/microsoft.graph.agentIdentityBlueprintPrincipal` |
| Create Agent Identity | `POST` | `/servicePrincipals/microsoft.graph.agentIdentity` |
| Add FIC to Blueprint | `POST` | `/applications/{id}/microsoft.graph.agentIdentityBlueprint/federatedIdentityCredentials` |
| List Agent Identities | `GET` | `/servicePrincipals/microsoft.graph.agentIdentity` |
| Grant app permission | `POST` | `/servicePrincipals/{id}/appRoleAssignments` |
| Grant delegated permission | `POST` | `/oauth2PermissionGrants` |
| Delete Agent Identity | `DELETE` | `/servicePrincipals/{id}` |
| Delete Blueprint | `DELETE` | `/applications/{id}` |

Base URL: `https://graph.microsoft.com/v1.0`.

## Required Graph Permissions

| Permission | Purpose |
|-----------|---------|
| `AgentIdentityBlueprint.Create` | Create Blueprints |
| `AgentIdentityBlueprint.ReadWrite.All` | Read/update Blueprints |
| `AgentIdentityBlueprintPrincipal.Create` | Create BlueprintPrincipals |
| `AgentIdentity.Create.All` | Create Agent Identities |
| `AgentIdentity.ReadWrite.All` | Read/update Agent Identities |
| `Application.ReadWrite.All` | Blueprint CRUD on application objects |
| `AppRoleAssignment.ReadWrite.All` | Grant application permissions |
| `DelegatedPermissionGrant.ReadWrite.All` | Grant delegated permissions |

Grant admin consent (required for application permissions):

```bash
az ad app permission admin-consent --id <client-id>
```

After admin consent, tokens may not include new claims for 30–120 seconds — retry with exponential backoff.

## Best Practices

1. **Always create BlueprintPrincipal after Blueprint** — not auto-created.
2. **Use typed endpoints** (`/applications/microsoft.graph.agentIdentityBlueprint`) instead of raw `/applications` with `@odata.type`.
3. **Credentials live on the Blueprint** — Agent Identities can't hold secrets/certs (`PropertyNotCompatibleWithAgentIdentity`).
4. **Include `OData-Version: 4.0`** on every Graph request.
5. **Use Workload Identity Federation for production** — client secrets only for local dev.
6. **Set `identifierUris: ["api://{appId}"]` on the Blueprint** before OAuth2 scope resolution.
7. **Never use Azure CLI tokens** for Agent Identity APIs — `Directory.AccessAsUser.All` causes hard 403.
8. **Use `fmi_path`** with `client_credentials` — NOT RFC 8693 `urn:ietf:params:oauth:grant-type:token-exchange` (returns `AADSTS82001`).
9. **Always use `/.default` scope** in both steps of the exchange — individual scopes fail.
10. **Step 1 targets the Agent Identity's home tenant** in cross-tenant flows.
11. **Grant permissions per Agent Identity**, not to the BlueprintPrincipal.
12. **Handle permission-propagation delays** — retry 403s with 30–120s backoff after admin consent.
13. **Keep the Entra SDK for AgentID on localhost** — never expose via LoadBalancer or Ingress.

## Troubleshooting

| Error | Cause | Fix |
|-------|-------|-----|
| `AADSTS82001` | Used RFC 8693 token-exchange grant | Use `client_credentials` with `fmi_path` |
| `AADSTS700211` | Step 1 parent token targeted wrong tenant | Target Agent Identity's home tenant |
| `AADSTS50013` | OBO user token targets Graph, not Blueprint | Use `api://{blueprint_app_id}/access_as_user` |
| `AADSTS65001` | Missing grant or used individual scopes | Use `/.default` and verify `oauth2PermissionGrants` |
| `403 Authorization_RequestDenied` | No grant on this Agent Identity | Add via `appRoleAssignments` or `oauth2PermissionGrants` |
| `PropertyNotCompatibleWithAgentIdentity` | Tried to add credential to Agent Identity SP | Put credentials on the Blueprint |
| `Agent Blueprint Principal does not exist` | BlueprintPrincipal not created | Step 2 of the Core Workflow |
| `AADSTS650051` on admin consent | SP already exists from partial consent | Grant directly via `appRoleAssignments` |

## References

| File | Contents |
|------|----------|
| [references/runtime-token-exchange.md](references/runtime-token-exchange.md) | Two-step `fmi_path` exchange: autonomous + OBO, cross-tenant |
| [references/oauth2-token-flow.md](references/oauth2-token-flow.md) | MI + WIF (production) and client secret (local dev) |
| [references/obo-blueprint-setup.md](references/obo-blueprint-setup.md) | Configuring the Blueprint as an OAuth2 API for OBO |
| [references/sdk-sidecar.md](references/sdk-sidecar.md) | Microsoft Entra SDK for AgentID — architecture, configuration, endpoints |
| [references/sdk-sidecar-deployment.md](references/sdk-sidecar-deployment.md) | SDK code patterns (Python/TypeScript), Docker/Kubernetes manifests, security, troubleshooting |
| [references/known-limitations.md](references/known-limitations.md) | Documented gaps organized by category |

### External Links

| Resource | URL |
|----------|-----|
| Agent ID Setup Guide | https://learn.microsoft.com/en-us/entra/agent-id/identity-platform/agent-id-setup-instructions |
| AI-Guided Setup | https://learn.microsoft.com/en-us/entra/agent-id/identity-platform/agent-id-ai-guided-setup |
| Microsoft Entra SDK for AgentID | https://learn.microsoft.com/en-us/entra/msidweb/agent-id-sdk/overview |
| Microsoft.Identity.Web.AgentIdentities (.NET) | https://github.com/AzureAD/microsoft-identity-web/blob/master/src/Microsoft.Identity.Web.AgentIdentities/README.AgentIdentities.md |