Builds on Quickstart 3 by adding DAB database policies that filter data per user. Users authenticate with Microsoft Entra ID. The web app sends a bearer token to DAB. DAB still connects to SQL using SAMI.
The difference in this quickstart is policy enforcement inside DAB. The API reads claims from the token and applies database policies to restrict what data a user can access. Each authenticated user only sees their own todos.
- Apply DAB database policies (
@item.Owner eq @claims.preferred_username) - Enforce per-user data isolation with zero custom API code
- Use MSAL in a SPA with auto-redirect (no manual login)
- Pass bearer tokens from web → API
| Hop | Local | Azure |
|---|---|---|
| User → Web | Entra ID (auto-redirect) | Entra ID (auto-redirect) |
| Web → API | Bearer token | Bearer token |
| API → SQL | SQL Auth + policy | SAMI + policy |
flowchart LR
U[User]
subgraph Microsoft Entra
E[App Registration]
end
subgraph Azure Container Apps
W[Web App]
A[Data API builder<br/><i>With Database Policy</i>]
end
subgraph Azure SQL
S[(Database)]
end
U <-->|Login| E
E -.-> W
U -->|OAuth| W -->|Bearer Token| A
A -->|SAMI| S
Considerations on DAB Policy: Identity now flows through the system. DAB enforces data access rules based on user claims. The database trusts DAB's identity, but DAB is responsible for applying user-level filtering.
- .NET 10+ SDK
- Aspire workload —
dotnet workload install aspire - Azure CLI (for Entra ID setup)
- Data API Builder CLI —
dotnet tool restore - Docker Desktop
- PowerShell
Azure Permissions Required: Create app registrations in Entra ID.
dotnet tool restore
az login
dotnet run --project aspire-apphostOn first run, Aspire detects that Entra ID isn't configured and offers to run azure/entra-setup.ps1 interactively. This creates the app registration, updates config.js and dab-config.json, then starts normally.
The web app auto-redirects to Microsoft login. Once signed in, all API calls include bearer tokens. Unlike Quickstart 3, each user now only sees rows they own.
pwsh ./azure-infra/azure-up.ps1The preprovision hook runs entra-setup.ps1 automatically. During teardown via azure-down.ps1, the postdown hook runs entra-teardown.ps1 to delete the app registration.
To tear down resources:
pwsh ./azure-infra/azure-down.ps1DAB applies this policy on every read, update, and delete:
@item.Owner eq @claims.preferred_username
This means the signed-in user can only access rows where Owner matches their Entra ID UPN. No custom API code required.
To restrict access to rows where the Owner matches the user's subject claim:
{
"entities": {
"Todos": {
"permissions": [
{
"role": "authenticated",
"actions": [
{
"action": "read",
"policy": {
"database": "@item.Owner eq @claims.preferred_username"
}
}
]
}
]
}
}
}| File | Change |
|---|---|
api/dab-config.json |
Changes role from anonymous to authenticated; adds policy to read, update, and delete actions |
web/auth.js |
New — MSAL with auto-redirect (no manual login button) |
web/index.html |
Adds MSAL CDN, removes add-form (shows after auth), adds auth.js script |
web/app.js |
Adds initializeApp() async init with auth; updateUI() for signed-in state |
web/dab.js |
Sends bearer token with every API call via getAuthHeaders() |
web/config.js |
Adds clientId and tenantId for MSAL configuration |
QS3 had no login at all — the web was fully anonymous. QS4 introduces the entire auth flow: MSAL, auto-redirect, bearer tokens,
authenticatedrole, and per-user policies.
| Quickstart | Inbound | Outbound | Security |
|---|---|---|---|
| Quickstart 1 | Anonymous | SQL Auth | — |
| Quickstart 2 | Anonymous | Managed Identity | — |
| Quickstart 3 | Entra ID | Managed Identity | — |
| This repo | Entra ID | Managed Identity | API RLS |
| Quickstart 5 | Entra ID | Managed Identity | DB RLS |