SOP: Azure SWA + Container Apps Authentication
TL;DR: When API calls return 401 Unauthorized, check both the SWA config AND the Container App authConfig. Both layers can block requests independently.
Problem Summary
Azure Static Web Apps (SWA) with a linked Container Apps backend has two authentication layers that can independently block API requests:
- SWA Layer (
staticwebapp.config.json) - Routes and roles - Container App Layer (
authConfigresource in Bicep) - Platform-level auth
Even if one layer allows anonymous access, the other can still enforce authentication.
Common Symptoms
| Symptom | Likely Cause |
|---|---|
401 on all /api/* routes | SWA config missing anonymous role OR Container App AAD enabled |
| 401 with valid SWA config | Container App authConfig has AAD identityProviders enabled |
| Timeout on API calls | Container App not running (check revision status) |
| Internal health checks pass, external 401 | Platform auth on Container App |
Configuration Files
1. SWA Config (frontend/staticwebapp.config.json)
{
"routes": [
{
"route": "/api/*",
"allowedRoles": ["anonymous", "authenticated"]
},
{
"route": "/*",
"allowedRoles": ["anonymous", "authenticated"]
}
]
}
[!WARNING] Do NOT include incomplete AAD settings with placeholders like
<TENANT_ID>. This breaks the config silently and may cause 401s.
2. Container App Auth (infra/modules/backend-aca.bicep)
For staging/POC (auth disabled at platform level):
resource authConfig 'Microsoft.App/containerApps/authConfigs@2023-05-01' = {
parent: backendApp
name: 'current'
properties: {
platform: {
enabled: false // Auth handled by application code
}
globalValidation: {
unauthenticatedClientAction: 'AllowAnonymous'
}
// NO identityProviders block for staging
}
}
For production (proper AAD auth):
resource authConfig 'Microsoft.App/containerApps/authConfigs@2023-05-01' = {
parent: backendApp
name: 'current'
properties: {
platform: {
enabled: true // Platform enforces auth
}
globalValidation: {
unauthenticatedClientAction: 'RedirectToLoginPage'
}
identityProviders: {
azureActiveDirectory: {
enabled: true
registration: {
clientId: '<REGISTERED_APP_CLIENT_ID>'
openIdIssuer: 'https://login.microsoftonline.com/<TENANT_ID>/v2.0'
}
validation: {
allowedAudiences: ['api://<APP_NAME>']
}
}
}
}
}
Debugging Checklist
When you see 401 Unauthorized:
- Check SWA config has
"allowedRoles": ["anonymous"]for/api/* - Check Container App authConfig has
platform.enabled: falsefor staging - Verify no AAD identityProviders in authConfig (staging only)
- Check container logs to see if requests reach the app
- Test internal vs external — internal health checks pass but external fails = platform auth
Useful Commands
# Check Container App status
az containerapp show --name "staging-env-api" --resource-group "engram-rg" \
--query "{state:properties.runningStatus,revision:properties.latestRevisionName}"
# View container logs (last 20 lines)
az containerapp logs show --name "staging-env-api" --resource-group "engram-rg" \
--type console --tail 20
# Test API directly (bypasses SWA)
curl "https://staging-env-api.gentleriver-dd0de193.eastus2.azurecontainerapps.io/health"
# Test through SWA
curl "https://engram.work/api/v1/agents"
Environment-Based Auth Strategy
| Environment | Platform Auth | Application Auth | Notes |
|---|---|---|---|
| Local/Dev | Off | Off (AUTH_REQUIRED=false) | Fastest iteration |
| Staging/POC | Off | Off | Validate system works |
| UAT | On | Optional | Test auth flow |
| Production | On | On | Full security |
References
- Azure SWA Authentication
- Container Apps Auth Config
- See also:
docs/sop/auth-environments-nist-ai-rmf.md