# Propagate Id Entra

> This example shows how to propagate a user's Entra ID identity end-to-end — from the browser, through an AI Foundry agent with MCP tools, through API Management, all the way to the backend API. No service accounts in the data path.

- **Type:** MCP server
- **Install:** `agentstack add mcp-ozgurkarahan-propagate-id-entra`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [ozgurkarahan](https://agentstack.voostack.com/s/ozgurkarahan)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [ozgurkarahan](https://github.com/ozgurkarahan)
- **Source:** https://github.com/ozgurkarahan/propagate-id-entra

## Install

```sh
agentstack add mcp-ozgurkarahan-propagate-id-entra
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Propagate ID Entra

**End-to-end identity propagation from browser through AI agents to backend APIs — no service accounts in the data path.**

[](https://learn.microsoft.com/azure/developer/azure-developer-cli/)
[](https://www.python.org/)
[](https://learn.microsoft.com/azure/azure-resource-manager/bicep/)
[](LICENSE)

> A proof-of-concept showing how a user's Entra ID token can flow from a browser, through an AI Foundry agent with MCP tools, through API Management, all the way to a backend API — preserving the caller's identity at every hop. Deployed with a single `azd up`.

> **📖 Identity Propagation series** — this repo is part of a series on end-to-end user identity propagation for AI agents: no service accounts in the data path, every action traceable to a real user. Read the story: [From Theory to Production: Salesforce Meta-Tool & Identity Propagation](https://www.linkedin.com/pulse/from-theory-production-salesforce-meta-tools-identity-ozgur-karahan-ch30e/). Companion repos: [snow-meta-tool](https://github.com/ozgurkarahan/snow-meta-tool) · [salesforce-meta-tool-identity-propagation](https://github.com/ozgurkarahan/salesforce-meta-tool-identity-propagation)

## Why identity propagation matters

Most AI agent integrations take a shortcut: the agent authenticates to backend systems with a shared service account. It works in a demo, but it means every order lookup, every record update, every API call lands in the audit log as the same technical user — regardless of who actually asked. The moment an agent can act on business systems, "who did this?" must have a real answer.

The service-account pattern also forces over-provisioning. Because one credential has to cover anything any user might do, it accumulates the union of everyone's permissions — a single high-value target that bypasses the per-user authorization your backends already enforce. And when auditors ask you to trace an AI-initiated action back to a person, a shared credential has nothing to offer.

Identity propagation flips this: the user's own Entra ID token travels with the request through every hop — browser, chat app, Foundry agent, APIM, backend API. Each layer validates the same delegated identity, the backend authorizes against the actual caller, and the audit trail names a human, not a bot.

| | Service-account pattern | Identity propagation (this repo) |
|---|---|---|
| **Audit trail** | Every action logged as the shared account | Every action traceable to the signed-in user |
| **Least privilege** | One credential with the union of all users' permissions | Each request carries only that user's permissions |
| **Per-user authorization** | Reimplemented (or skipped) in middleware | Enforced by the backend, per caller, at every hop |
| **Compliance** | Hard to satisfy SOX/GDPR/ISO traceability requirements | Individual accountability built into the data path |

## Architecture

```mermaid
flowchart TD
    Browser["Browser(MSAL.js SPA)"]
    Entra["Entra ID"]
    ChatApp["Chat App(FastAPI + Container App)"]
    Agent["AI Foundry Agent(gpt-4o)"]
    APIM["API Management"]
    MCP["/orders-mcpvalidate-jwt"]
    REST["/orders-api"]
    OAI["/openaiAI Gateway"]
    Orders["Orders API(FastAPI + Container App)"]
    AOI["Azure OpenAI"]

    Browser -- "1 Sign in" --> Entra
    Entra -- "access token" --> Browser
    Browser -- "2 POST /api/chat{message, token}" --> ChatApp
    ChatApp -- "3 Responses API(UserTokenCredential)" --> Agent
    Agent -- "4 MCP tool call(UserEntraToken)" --> APIM
    APIM --- MCP
    APIM --- REST
    APIM --- OAI
    MCP --> Orders
    REST --> Orders
    OAI -- "Managed Identity" --> AOI
```

## How Identity Flows

```mermaid
sequenceDiagram
    participant B as Browser
    participant E as Entra ID
    participant C as Chat App
    participant F as Foundry Agent
    participant A as APIM
    participant O as Orders API

    B->>E: Sign in (MSAL.js)
    E-->>B: Access token (aud=ai.azure.com)
    B->>C: POST /api/chat {message, access_token}
    Note over C: Wraps token inUserTokenCredential
    C->>F: responses.create()
    Note over F: Agent decides tocall MCP tool
    F->>A: MCP request + Bearer token(UserEntraToken passthrough)
    Note over A: validate-jwt(aud, issuer, signature)
    A->>O: Forward request + JWT claims
    O-->>A: Order data
    A-->>F: MCP response
    F-->>C: Agent response
    C-->>B: Chat reply
```

| Hop | Auth Type | User Identity Preserved? |
|-----|-----------|--------------------------|
| Browser → Chat App → Foundry | Delegated (MSAL.js access token) | Yes |
| Foundry → APIM MCP | UserEntraToken passthrough | Yes |
| APIM → Azure OpenAI | Managed Identity (service-to-service) | No |

> [!IMPORTANT]
> No OAuth2 client credentials, no consent prompts, no client secrets, no refresh token expiry. The user's existing Entra token is passed directly at every hop via a **UserEntraToken** connection.

## Quick Start

> [!TIP]
> `azd up` does everything: provisions Azure resources via Bicep, builds and deploys containers to ACR, then runs a post-provision hook to create the Entra app registration and Foundry agent.

### Prerequisites

- **Azure subscription** with Owner/Contributor access
- **Azure CLI** (`az`) — logged in
- **Azure Developer CLI** (`azd`)
- **Python** 3.9+
- **Git**

Docker is not required locally — container builds run remotely on ACR.

### Deploy

```bash
git clone https://github.com/ozgurkarahan/propagate-id-entra.git
cd propagate-id-entra
azd env new propagate-id-entra
azd up
```

### Verify

```bash
python scripts/verify_deployment.py
python scripts/test-agent.py
```

## What `azd up` Does

```mermaid
flowchart LR
    P["azd provision"]
    D["azd deploy"]
    H["postprovision hook"]

    P -- "Bicep modules(13 modules, 4 tiers)" --> D
    D -- "Build + deployOrders API & Chat App" --> H
    H -- "1. Entra app registration2. Foundry agent creation3. Chat App env vars" --> Done["Ready"]
```

## Project Structure

Click to expand

| Path | Description |
|------|-------------|
| `infra/main.bicep` | Subscription-scoped Bicep orchestrator |
| `infra/modules/` | 13 Bicep modules (APIM, Cognitive, Container Apps, etc.) |
| `infra/policies/` | APIM policies (JWT validation, AI Gateway, RFC 9728 PRM) |
| `src/orders-api/` | FastAPI Orders CRUD backend (6 endpoints, 8 seed orders) |
| `src/chat-app/` | FastAPI backend + vanilla JS SPA with MSAL.js |
| `hooks/postprovision.py` | Entra app registration + Foundry agent creation |
| `scripts/` | Deployment verification, diagnostics, agent testing |
| `docs/` | Deep-dive architecture, identity & security, reference docs |

## Learn More

- [**Identity & Security Architecture**](docs/identity-security.md) — Entra app registration, managed identities, JWT validation, RFC 9728, security design decisions
- [**Deep Dive**](docs/deep-dive.md) — ARM resource details, data flows, step-by-step build guide
- [**AGENT.md**](AGENT.md) — Architecture diagrams, auth flow details, IaC principles, development reference

## License

[MIT](LICENSE)

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [ozgurkarahan](https://github.com/ozgurkarahan)
- **Source:** [ozgurkarahan/propagate-id-entra](https://github.com/ozgurkarahan/propagate-id-entra)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-ozgurkarahan-propagate-id-entra
- Seller: https://agentstack.voostack.com/s/ozgurkarahan
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
