Reference implementation that hosts a Microsoft Entra Agent Identity demo on Azure App Service for Linux using the sidecar containers feature. The same demo is commonly run on Azure Container Apps; this repo shows how to do it on App Service instead.
The app proves Entra Agent Identity end-to-end with 5 clickable steps:
- Get a Bearer token as the Agent Identity (not as the Blueprint).
- Decode the JWT and verify Agent-specific claims (
xms_par_app_azp,idtyp=app, etc.). - Call Microsoft Graph
/v1.0/users?$top=3as the Agent. - Negative comparison — same Graph call without
AgentIdentity(token reverts to Blueprint). - Security boundary — try to mint a token for an Agent parented by a different Blueprint and watch Entra reject it (
AADSTS700213).
User (browser)
│ HTTPS
▼
┌─────────────────────────────────────────┐
│ App Service (Linux, custom container) │
│ │
│ main: agent (FastAPI, port 8000) ──▶ │
│ │
│ sidecar: entra-sdk auth-sidecar (5000) │
│ │
└──────────────────┼──────────────────────┘
│ OAuth client_credentials + AgentIdentity
▼
login.microsoftonline.com → graph.microsoft.com
- Main container — your FastAPI app, built from this repo's
Dockerfileand pushed to ACR. - Sidecar container —
mcr.microsoft.com/entra-sdk/auth-sidecar:1.0.0-azurelinux3.0-distroless. - They share
localhost, so the agent reaches the sidecar athttp://localhost:5000.
| File | Purpose |
|---|---|
app.py |
FastAPI app — backend routes + embedded HTML/JS for the 5-step UI |
Dockerfile |
python:3.12-slim + fastapi + uvicorn + httpx, exposes 8000 |
.env.example |
Template for runtime env vars |
deploy.ps1 |
One-shot Azure deployment (RG → Plan → Web App → sidecar) |
README.md |
This file |
- Azure CLI (
az) logged into your tenant. - An Azure subscription where you can create resource groups and App Service plans.
- An Azure Container Registry with the agent image pushed (e.g.
<YOUR_ACR>.azurecr.io/agent-demo:v1). Build & push from this folder:az acr build -r <YOUR_ACR> -t agent-demo:v1 .
- Entra app registrations already created:
- A Blueprint app (the credential holder).
- An Agent Identity app (credential-less child of the Blueprint).
- Optionally, a foreign Agent app under a different Blueprint, for Step 5's negative test.
Edit the variables at the top of deploy.ps1:
| Variable | What it is |
|---|---|
$Subscription |
Azure subscription ID |
$ResourceGroup |
RG to create / reuse |
$WebAppName |
Globally unique under *.azurewebsites.net |
$AcrName |
Your ACR name (without .azurecr.io) |
$ImageTag |
Tag of the agent image to deploy |
$TenantId |
Entra tenant where the Blueprint and Agent live |
$BlueprintAppId |
App (client) ID of the Blueprint |
$AgentAppId |
App (client) ID of the Agent Identity |
$ForeignAgentAppId |
App ID of a foreign Agent (optional, for Step 5) |
$UseManagedIdentityForAcr |
$true for managed-identity ACR pull (preferred), $false for ACR admin user fallback |
az login --tenant <YOUR_TENANT_ID>
.\deploy.ps1The script:
- Creates the resource group.
- Creates a Linux App Service Plan (B1 — sidecars require Basic+).
- Creates a Web App with the agent image as the main container.
- Configures ACR pull (managed identity or admin credentials).
- Sets app settings (
TENANT_ID,BLUEPRINT_APP_ID,AGENT_APP_ID,FOREIGN_AGENT_APP_ID,SIDECAR_URL=http://localhost:5000,WEBSITES_PORT=8000). - Adds the
auth-sidecarsidecar container on port 5000. - Restarts and prints the URL.
az acr build -r <YOUR_ACR> -t agent-demo:vNEXT .
az webapp config container set -g <YOUR_RG> -n <YOUR_WEBAPP> `
--container-image-name <YOUR_ACR>.azurecr.io/agent-demo:vNEXT
az webapp restart -g <YOUR_RG> -n <YOUR_WEBAPP>az group delete --name <YOUR_RG> --yes --no-wait| Aspect | Container Apps | App Service |
|---|---|---|
| Multi-container | Native containers[] |
Sidecar containers feature (GA) |
| Hostname | *.azurecontainerapps.io |
*.azurewebsites.net |
| Scale-to-zero | Yes (KEDA) | No on B1; needs scale rules on Premium |
| Min plan tier | Consumption | B1 (sidecars require Basic+) |
| App code | — | identical |
| Entra config | — | identical |
The application code, env-var contract, and 5-step UX are identical across both hosting models. Only the deployment plumbing differs.
ACRTokenRetrievalFailure/ImagePullFailure— your account doesn't haveMicrosoft.Authorization/roleAssignments/writeon the ACR. Either ask the ACR owner to grantAcrPullto the web app's managed identity, or set$UseManagedIdentityForAcr = $falseto use ACR admin credentials.- Application Error after deploy — check
az webapp log tail -g <RG> -n <WEBAPP>. Most common causes: image pull failure (above), missing env vars, or sidecar not yet started. - Sidecar didn't start — list sidecars with
az webapp sitecontainers list -g <RG> -n <WEBAPP> -o table.
.envis gitignored. Never commit real tenant / app IDs or secrets.- The Agent Identity is credential-less by design — only the Blueprint holds a
secret, and the sidecar uses it together with
AgentIdentity={agentAppId}to request Agent-scoped tokens from Entra. - Step 5 (security boundary) demonstrates that a Blueprint cannot mint tokens for Agents it does not parent — Entra enforces this server-side.