Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/controller/mcp_route_security_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ func buildWWWAuthenticateHeaderValue(metadata *aigv1a1.ProtectedResourceMetadata
// Add resource_metadata as per RFC 9728 Section 5.1.
headerValue = fmt.Sprintf(`%s, resource_metadata="%s"`, headerValue, resourceMetadataURL)

if len(metadata.ScopesSupported) > 0 {
// Add scope as per RFC 6750 Section 3.
headerValue = fmt.Sprintf(`%s, scope="%s"`, headerValue, strings.Join(metadata.ScopesSupported, " "))
}

return headerValue
}

Expand Down
24 changes: 24 additions & 0 deletions internal/controller/mcp_route_security_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,30 @@ func Test_buildWWWAuthenticateHeaderValue(t *testing.T) {
},
expected: `Bearer error="invalid_request", error_description="No access token was provided in this request", resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/v1/mcp/endpoint"`,
},
{
name: "with empty scopes supported",
metadata: &aigv1a1.ProtectedResourceMetadata{
Resource: "https://api.example.com/mcp",
ScopesSupported: []string{},
},
expected: `Bearer error="invalid_request", error_description="No access token was provided in this request", resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/mcp"`,
},
{
name: "with single scope supported",
metadata: &aigv1a1.ProtectedResourceMetadata{
Resource: "https://api.example.com/mcp",
ScopesSupported: []string{"read"},
},
expected: `Bearer error="invalid_request", error_description="No access token was provided in this request", resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/mcp", scope="read"`,
},
{
name: "with multiple scopes supported",
metadata: &aigv1a1.ProtectedResourceMetadata{
Resource: "https://api.example.com/mcp",
ScopesSupported: []string{"read", "write"},
},
expected: `Bearer error="invalid_request", error_description="No access token was provided in this request", resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/mcp", scope="read write"`,
},
}

for _, tt := range tests {
Expand Down
14 changes: 12 additions & 2 deletions tests/e2e/mcp_route_oauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,12 @@ func TestMCPRouteOAuth(t *testing.T) {
require.Contains(t, wwwAuthHeader, "Bearer", "WWW-Authenticate header should contain Bearer scheme")

// Validate WWW-Authenticate header contains resource_metadata parameter.
require.Contains(t, wwwAuthHeader, "resource_metadata", "WWW-Authenticate header should contain resource_metadata parameter")
require.Contains(t, wwwAuthHeader, `resource_metadata="https://foo.bar.com/.well-known/oauth-protected-resource/mcp"`,
"WWW-Authenticate header should contain resource_metadata parameter")
t.Logf("WWW-Authenticate header: %s", wwwAuthHeader)

// Validate WWW-Authenticate header contains scope parameter.
require.Contains(t, wwwAuthHeader, `scope="echo sum countdown"`, "WWW-Authenticate header should contain resource_metadata parameter")
t.Logf("WWW-Authenticate header: %s", wwwAuthHeader)
})

Expand Down Expand Up @@ -320,7 +325,12 @@ func TestMCPRouteOAuth(t *testing.T) {
require.Contains(t, wwwAuthHeader, "Bearer", "WWW-Authenticate header should contain Bearer scheme")

// Validate WWW-Authenticate header contains resource_metadata parameter.
require.Contains(t, wwwAuthHeader, "resource_metadata", "WWW-Authenticate header should contain resource_metadata parameter")
require.Contains(t, wwwAuthHeader, `resource_metadata="https://foo.bar.com/.well-known/oauth-protected-resource/mcp"`,
"WWW-Authenticate header should contain resource_metadata parameter")
t.Logf("WWW-Authenticate header: %s", wwwAuthHeader)

// Validate WWW-Authenticate header contains scope parameter.
require.Contains(t, wwwAuthHeader, `scope="echo sum countdown"`, "WWW-Authenticate header should contain resource_metadata parameter")
t.Logf("WWW-Authenticate header: %s", wwwAuthHeader)
})
}
Loading