Skip to content

Commit 953d315

Browse files
committed
feat: add Application ID URI parameter and update policies for JWT audience validation
1 parent 7ef2909 commit 953d315

4 files changed

Lines changed: 20 additions & 1 deletion

File tree

labs/mcp-prm-oauth/main.bicep

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ module mcpEntraAppModule 'src/bicep/identity/mcp-entra-app.bicep' = if (empty(mc
234234
tenantId: subscription().tenantId
235235
userAssignedIdentityPrincipleId: managedIdentityModule.outputs.identityPrincipalId
236236
webAppName: mcpServerContainerApp.name
237+
// Application ID URI == PRM resource == JWT audience (all resolve to https://<apim>.azure-api.net/<mcpPrmPath>)
238+
applicationIdUri: '${apimModule.outputs.gatewayUrl}/${mcpPrmPath}'
237239
}
238240
}
239241

labs/mcp-prm-oauth/src/bicep/apim-mcp/mcp-api.policy.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
<!-- Validate Azure AD JWT Token -->
1010
<validate-azure-ad-token tenant-id="{{McpTenantId}}" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized">
1111
<audiences>
12+
<!-- v2 tokens carry the appId (GUID) as aud; the Application ID URI is accepted too. -->
1213
<audience>{{McpClientId}}</audience>
14+
<audience>{{APIMGatewayURL}}/{{McpApiPath}}</audience>
1315
</audiences>
1416
</validate-azure-ad-token>
1517
</inbound>

labs/mcp-prm-oauth/src/bicep/apim-mcp/mcp-prm.policy.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"header"
2626
},
2727
scopes_supported = new[] {
28-
"{{McpClientId}}/user_impersonate"
28+
"{{APIMGatewayURL}}/{{McpApiPath}}/user_impersonate"
2929
}
3030
});
3131
}</set-body>

labs/mcp-prm-oauth/src/bicep/identity/mcp-entra-app.bicep

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ param userAssignedIdentityPrincipleId string
1515
@description('The container app name for callback URL configuration')
1616
param webAppName string
1717

18+
@description('The Application ID URI to expose (must match the PRM resource and the JWT audience). Example: https://<apim>.azure-api.net/mcp')
19+
param applicationIdUri string
20+
1821
var loginEndpoint = environment().authentication.loginEndpoint
1922
var issuer = '${loginEndpoint}${tenantId}/v2.0'
2023

@@ -26,6 +29,10 @@ resource containerApp 'Microsoft.App/containerApps@2023-11-02-preview' existing
2629
resource mcpEntraApp 'Microsoft.Graph/applications@v1.0' = {
2730
displayName: mcpAppDisplayName
2831
uniqueName: mcpAppUniqueName
32+
// Application ID URI. Aligns with the PRM 'resource' and the validate-jwt audience.
33+
identifierUris: [
34+
applicationIdUri
35+
]
2936
api: {
3037
oauth2PermissionScopes: [
3138
{
@@ -65,6 +72,14 @@ resource mcpEntraApp 'Microsoft.Graph/applications@v1.0' = {
6572
'https://${containerApp.properties.configuration.ingress.fqdn}/auth/callback'
6673
]
6774
}
75+
// Public client (Authorization Code + PKCE, no client secret) for MCP Inspector.
76+
// Registering these as public-client (not SPA) redirect URIs avoids AADSTS9002327.
77+
publicClient: {
78+
redirectUris: [
79+
'http://localhost:6274/oauth/callback'
80+
'http://localhost:6274/oauth/callback/debug'
81+
]
82+
}
6883

6984
resource fic 'federatedIdentityCredentials@v1.0' = {
7085
name: '${mcpEntraApp.uniqueName}/msiAsFic'

0 commit comments

Comments
 (0)