Skip to content

MCP OAuth cannot complete on 17.3.0: plugin-auth passes validAudiences, which @better-auth/oauth-provider 1.7.2 no longer reads — every resource= request fails with invalid_target … is not configured #16530

Description

@yinlianghui

Summary

MCP OAuth cannot complete on 17.3.0: the authorization server rejects every MCP client with invalid_target: requested resource <mcp url> is not configured. @objectstack/plugin-auth configures @better-auth/oauth-provider with validAudiences: [authIssuer, mcpResourceUrl], but oauth-provider 1.7.2 (the version plugin-auth declares via ^1.7.2) no longer has that option — the string validAudiences does not occur anywhere in its dist. In 1.7.2 an RFC 8707 resource is resolved from the oauthResource table (sys_oauth_resource), and enforcePerClientResources defaults to true, so each OAuth client must also be linked in oauthClientResource. Neither row is ever written, so any client that sends resource= (Claude Code does) is refused at /oauth2/authorize.

This is independent of http/https and of the desktop-app must be https refusal — it is the next wall behind it.

Environment

  • hotcrm 789a7324 (main), @objectstack/* 17.3.0, better-auth 1.7.2, @better-auth/oauth-provider 1.7.2 (hoisted; plugin-auth declares ^1.7.2 for both)
  • dev server objectstack dev -p 4001 with OS_AUTH_URL=https://localhost:4443, behind a local TLS reverse proxy (self-signed CA trusted in the system keychain)
  • Client: Claude Code desktop (Claude for Mac 1.46388.x, Claude Code 2.1.260), MCP entry {type: http, url: https://localhost:4443/api/v1/mcp}, no headers

Reproduction

  1. Discovery is correct after OS_AUTH_URL:

    • /.well-known/oauth-protected-resource{"resource":"https://localhost:4443/api/v1/mcp","authorization_servers":["https://localhost:4443/api/v1/auth"], …}
    • /.well-known/oauth-authorization-server → issuer / authorization / token / registration endpoints all https://localhost:4443/api/v1/auth/…
    • GET /api/v1/mcp401, www-authenticate: Bearer realm="ObjectStack MCP", resource_metadata="https://localhost:4443/.well-known/oauth-protected-resource"
  2. In Claude Code: /mcpConnect. Dynamic client registration succeeds (a new sys_oauth_application row Claude Code (hotcrm) with scopes ["openid","profile","email","offline_access","data:read","data:write","actions:execute"]), the system browser opens, and the flow ends on the error page:

    Authentication failed — Close this tab and try again from Claude Code.
    invalid_target: requested resource https://localhost:4443/api/v1/mcp is not configured

  3. Database after the attempt: sys_oauth_resource 0 rows, sys_oauth_client_resource 0 rows, sys_oauth_application 6 rows (one per Connect attempt over three days — a fresh client each time), sys_oauth_consent / sys_oauth_access_token / sys_oauth_refresh_token all 0. No token has ever been minted.

Where it happens

  • @objectstack/plugin-auth (dist, oauthProvider({...}) options): validAudiences: [this.getAuthIssuer(), this.getMcpResourceUrl()] with the comment "the AS only mints audiences it knows". No resources, clientRegistrationDefaultResources, enforcePerClientResources or resourcePrivileges are passed.
  • @better-auth/oauth-provider 1.7.2, token/authorize path: for every requested resource getResource(ctx, opts, identifier) reads the oauthResource model; a miss throws invalid_target … is not configured. Then resolveEnforcePerClientResources(opts){ value: true, source: "default" } and assertClientLinkedToResources requires an oauthClientResource row per client.
  • grep -c validAudiences node_modules/@better-auth/oauth-provider/dist/*.mjs → 0 in every file.

Expected

An MCP client following the advertised discovery documents (RFC 9728 → RFC 8414 → DCR → PKCE authorize with resource=<mcp url>) should reach the consent screen and receive a token audienced to the MCP resource. Concretely, plugin-auth should:

  • register the MCP resource (getMcpResourceUrl()) as an oauthResource row at boot (or via the plugin's resources option, whichever 1.7.2 honours), and
  • either set clientRegistrationDefaultResources: [mcpResourceUrl] so DCR-registered clients are linked automatically, or set enforcePerClientResources: false for the MCP resource — a client that registers anonymously one second before the login cannot be linked by an admin in between.

Side observations

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions