Moves enforcement into the database with SQL Row-Level Security. The authentication flow uses Microsoft Entra ID, and authorization is enforced by SQL.
Instead of DAB enforcing user-based filtering, SQL enforces it directly using RLS policies tied to the authenticated context. Even if an API misconfigures filtering logic, the database enforces row-level restrictions. This is the most robust model because authorization is guaranteed at the data layer.
- Create a SQL RLS filter predicate and security policy
- Push per-user access control into the database engine
- Remove DAB policies — the database enforces isolation directly
| Hop | Local | Azure |
|---|---|---|
| User → Web | Entra ID (auto-redirect) | Entra ID (auto-redirect) |
| Web → API | Bearer token | Bearer token |
| API → SQL | SQL Auth + RLS | SAMI + RLS |
flowchart LR
U[User]
subgraph Microsoft Entra
E[App Registration]
end
subgraph Azure Container Apps
W[Web App]
A[Data API builder]
end
subgraph Azure SQL
S[(Database<br/><i>With RLS Policy</i>)]
end
E -.-> W
U <-->|Login| E
U -->|OAuth| W -->|Bearer Token| A -->|SAMI| S
Considerations on Row-Level Security: RLS pushes access control into the database engine itself. Even if an API misconfigures filtering logic, the database enforces row-level restrictions. This is the most robust model because authorization is guaranteed at the data layer.
- .NET 8 or later
- 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 Entra ID isn't configured and walks you through setup. The script creates an app registration, updates config.js and dab-config.json, then starts normally.
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.ps1SQL Server enforces row-level access using a filter predicate:
CREATE FUNCTION dbo.UserFilterPredicate(@OwnerId sysname)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN SELECT 1 AS IsVisible WHERE @OwnerId = SUSER_SNAME();
CREATE SECURITY POLICY UserFilterPolicy
ADD FILTER PREDICATE dbo.UserFilterPredicate(Owner) ON dbo.Todos
WITH (STATE = ON);Even if DAB returns all rows, SQL only delivers those where Owner matches the database user. Authorization is guaranteed at the data layer.
| File | Purpose |
|---|---|
api/dab-config.json |
Removes DAB-level policy filtering for data actions |
database.sql |
Adds UserFilterPredicate function and UserFilterPolicy security policy |
The key behavior in this quickstart is that authorization is enforced in SQL with RLS rather than in DAB policy expressions.
erDiagram
Todos {
int TodoId PK
nvarchar Title
date DueDate
bit Completed
nvarchar Owner
}
The
Ownercolumn stores the Entra ID UPN. The RLS policy filters rows automatically at the SQL layer.