Skip to content

Embedded auth server issues tokens without audience claim when client omits RFC 8707 resource parameter #4794

@jerm-dro

Description

@jerm-dro

Summary

The embedded auth server issues incoming access tokens with an empty aud claim when clients don't send the optional RFC 8707 resource parameter in the token request. This causes VirtualMCPServer to reject tokens issued by its own auth server.

Problem

We have two configurations using the embedded auth server:

MCPServer with MCPExternalAuthConfig (works): The MCPServer's oidcConfig.inline does not set audience, so the incoming auth validator skips the audience check when no expected audience is configured (pkg/auth/token.go:947). Incoming tokens with empty aud claims pass validation.

VirtualMCPServer with inline authServerConfig (fails): The VirtualMCPServer requires audience in incomingAuth.oidcConfig.inline. Without it, the server fails config validation on startup:

{"level":"ERROR","msg":"Configuration validation failed: invalid configuration:\n  - incomingAuth.oidc.audience is required"}

With audience configured, the incoming auth validator checks the token's aud claim against the expected audience (pkg/auth/token.go:948-962) and rejects the token the auth server just issued, because the token's aud claim is empty.

Both use the same embedded auth server runtime and the same token handler (pkg/authserver/server/handlers/token.go). We confirmed by inspecting the VirtualMCPServer's issued incoming token in Redis that it has "Audience":[], "requested_audience":null, "granted_audience":[]. The MCPServer uses the same token handler, so it produces the same token shape. The auth server only populates the aud claim when the client sends a resource parameter (RFC 8707) in the token request. Since resource is optional per the spec, clients may not send it, and the token is issued without an audience even though AllowedAudiences is configured.

Proposed Fix

When no resource parameter is sent in the token request and AllowedAudiences contains exactly one entry, the auth server should default to granting that audience. The allowed audience is already derived from the server's resourceUrl, so the intended audience is unambiguous.

Reproduction

  1. Deploy a VirtualMCPServer with authServerConfig and incomingAuth.oidcConfig.inline.audience set
  2. Connect via a client that does not send resource in the token request
  3. OAuth flow completes — token exchange returns 200
  4. MCP request fails with 401 — incoming token has empty audience, validator expects the configured audience

Metadata

Metadata

Assignees

Labels

authenticationauthorizationbugSomething isn't workinggoPull requests that update go codevmcpVirtual MCP Server related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions