feat: Add JWT validation to APIM for managed identity authentication#154
Merged
willvelida merged 6 commits intomainfrom Nov 12, 2025
Merged
feat: Add JWT validation to APIM for managed identity authentication#154willvelida merged 6 commits intomainfrom
willvelida merged 6 commits intomainfrom
Conversation
- Added validate-jwt policies to all 4 backend APIs (Weight, Activity, Sleep, Food) - Implemented choose policy for dual authentication (JWT OR subscription key) - Uses Azure AD tenant OpenID config for token validation - Parameterized tenantId and jwtAudience using environment() function - Maintains backward compatibility with subscription keys - Created decision record documenting architecture and rationale - Updated README with APIM authentication capability Related to #152
- Replace inline policy XML with loadTextContent() in Bicep files - Add policy-jwt-auth.xml with JWT validation logic - Add policy-subscription-key.xml for backward compatibility - Use replace() to substitute placeholders with Bicep variables - Improves maintainability and testability of policies All 4 APIs refactored: Weight, Activity, Sleep, Food
- Create apim-named-values.bicep module for centralized Named Values
- Deploy Named Values conditionally based on enableManagedIdentityAuth
- Update policy XML to use {{openid-config-url}}, {{jwt-audience}}, {{jwt-issuer}}
- Remove string replace() calls from Bicep policy resources
- Remove unused openidConfigUrl and jwtIssuer variables
- Remove Bicep linter suppressions (no longer needed)
Benefits:
- APIM-native approach with runtime flexibility
- Cleaner Bicep files (no triple replace() calls)
- Values visible in Azure Portal for troubleshooting
- Can update Named Values without redeploying Bicep
- Add tenantId parameter to all 4 API parameter files (default empty string) - Enable managed identity authentication (enableManagedIdentityAuth=true) - Pass tenantId from GitHub Actions AZURE_TENANT_ID secret via workflow - Add tenantId output to retrieve-container-image-dev jobs - Update validate, preview, and deploy steps with tenantId parameter Workflow will override empty tenantId with actual value from secret
- Add parameter preparation step in workflow templates to merge tenantId from secrets - Remove tenantId from job outputs (secrets can't be passed through outputs) - Use jq to merge user parameters with tenantId before deployment - Fixes double-slash in OpenID config URL (https://login.microsoftonline.com//v2.0)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements JWT validation in Azure API Management using APIM Named Values pattern for all 4 APIs (Weight, Activity, Sleep, Food). This enables Managed Identity authentication for the future Blazor UI while maintaining backward compatibility with subscription key authentication.
Changes
Infrastructure
New Module:
infra/modules/apim/apim-named-values.bicepopenid-config-url,jwt-audience,jwt-issuerenableManagedIdentityAuth = trueenvironment().authentication.loginEndpointfor multi-cloud supportUpdated API Bicep Files (Weight, Activity, Sleep, Food):
apim-named-valuesreplace()calls)loadTextContent()onlyUpdated Policy XML Files (all 4 APIs):
{{openid-config-url}},{{jwt-audience}},{{jwt-issuer}}<choose>logic: JWT validation for Bearer tokens, subscription key fallback for othersUpdated Parameter Files (all 4 APIs):
enableManagedIdentityAuth = truetenantId = ''(empty default, overridden by workflow)CI/CD Workflows
Enhanced Workflow Templates:
template-bicep-validate.ymltemplate-bicep-whatif.ymltemplate-bicep-deploy.ymltenantIdfrom secrets usingjqUpdated API Workflows (all 4):
tenantIdfrom job outputstenantIdfrom parameters JSONtenantIdinjection automaticallyDocumentation
Decision Record:
docs/decision-records/2025-11-12-apim-named-values-for-jwt-config.mdCommon Resolutions:
.specify/memory/common-resolutions.mdTesting Results ✅
Deployment Status
APIM Named Values Verification
✅ No double slashes - tenantId injection working correctly!
JWT Authentication Testing
Test Setup:
Results:
/weight/api/weight/activity/api/activity/sleep/api/sleep/food/api/foodAnalysis:
Backward Compatibility
<otherwise>clause for subscription key fallbackDeployment Notes
@013-apim-managed-identityto test updated templates@mainafter mergetenantId = ''- actual value injected by workflowsenableManagedIdentityAuth = trueImplementation Highlights
Why Named Values Instead of String Replacement?
replace()calls and linter suppressionsWorkflow Secret Passing Pattern
GitHub Actions doesn't allow secrets in reusable workflow
with:blocks or joboutputs:. Solution:Checklist
@mainRelated
docs/decision-records/2025-11-12-apim-named-values-for-jwt-config.md