Authentication Troubleshooting
Architecture
-
Browser → MSAL.js (PKCE flow) → JWT with Chat.ReadWrite scope
-
Frontend → Backend (JWT Bearer token)
-
Backend → Foundry Agent Service (ManagedIdentityCredential)
Common Issues
Issue Cause Fix
401 on /api/*
Token missing scope Verify Chat.ReadWrite scope in token
ManagedIdentityCredential error locally Wrong environment Set ASPNETCORE_ENVIRONMENT=Development
Token popup blocked Browser settings Allow popups for localhost
Silent token fails No cached token Fallback to popup (handled by useAuth)
Backend: JWT Validation
Accepts both audience formats:
options.TokenValidationParameters.ValidAudiences = new[] { builder.Configuration["AzureAd:ClientId"], $"api://{builder.Configuration["AzureAd:ClientId"]}" };
Backend: Credential Strategy
TokenCredential credential = env.IsDevelopment() ? new ChainedTokenCredential( new AzureCliCredential(), new AzureDeveloperCliCredential()) // Supports 'azd auth login' : new ManagedIdentityCredential();
Local development: Requires az login or azd auth login to work.
Why ChainedTokenCredential: Avoids DefaultAzureCredential 's unpredictable "fail fast" mode. Provides explicit, debuggable credential chain.
Frontend: MSAL Pattern
// Always try silent first try { const { accessToken } = await instance.acquireTokenSilent({ ...tokenRequest, account: accounts[0] }); return accessToken; } catch { // Fallback to popup const { accessToken } = await instance.acquireTokenPopup(tokenRequest); return accessToken; }
Debugging Steps
-
Check token contents: https://jwt.ms
-
Verify scope: Token should have Chat.ReadWrite
-
Check audience: Should match client ID or api://{clientId}
-
Verify Entra app: Check redirect URIs in Azure Portal
Environment Variables
Frontend (.env.local ):
VITE_ENTRA_SPA_CLIENT_ID=... VITE_ENTRA_TENANT_ID=...
Backend (.env ):
AzureAd__ClientId=... AzureAd__TenantId=...
Regenerate: Run azd up to recreate Entra app and .env files.
Related Skills
-
writing-csharp-code - Backend JWT validation and credential patterns
-
writing-typescript-code - Frontend MSAL integration and useAuth hook
-
deploying-to-azure - Entra app provisioning and RBAC configuration