Skip to content

Bind access tokens to an RFC 8707 resource indicator - #19

Draft
RhysSullivan wants to merge 1 commit into
mainfrom
workos-rfc8707-resource-audience
Draft

Bind access tokens to an RFC 8707 resource indicator#19
RhysSullivan wants to merge 1 commit into
mainfrom
workos-rfc8707-resource-audience

Conversation

@RhysSullivan

Copy link
Copy Markdown

A dynamically registered MCP client could not reach a resource server. The emulator issued tokens whose aud was the DCR client's own id, while a resource server verifies against its own client id, so every token was refused as invalid_token and re-authenticating just minted another wrong-audience client.

Change

A client that sends an RFC 8707 resource indicator to /oauth2/authorize now gets a token bound to that resource. That is the point of the mechanism: the resource server admits the token without knowing anything about the client that asked for it.

Three parts:

  • resource is carried on the authorization code, so it survives to the token endpoint.
  • The consent page passes it through as a hidden field. It previously dropped it, so only the login_hint fast path could carry a resource at all and nothing downstream ever set a resource audience.
  • The session records the binding, so a refresh renews a token the same resource server still accepts.

Precedence is resourceEMULATE_WORKOS_AUDIENCE → requesting client. Absent a resource indicator nothing changes for existing callers.

Tests

binds an access token to the RFC 8707 resource a client asked for covers the bound token, the refresh preserving the binding, and the unbound case still resolving to the requesting client. Confirmed to fail before the change (JWTClaimValidationFailed: unexpected "aud" claim value).

16 tests pass in @emulators/workos; the package lints with 0 errors.

web#lint fails on this branch, but it fails identically on a clean main — pre-existing and unrelated to this change, which touches only @emulators/workos.

Docs

skills/workos/SKILL.md updated for the new precedence. The other doc surfaces (README, web docs, CLI help) don't mention audience behaviour.

A client that names a resource at /oauth2/authorize now receives a token
whose aud is that resource, and a refresh renews the same binding. This is
what lets a dynamically registered MCP client reach a resource server that
has never seen its client id.

The consent page previously dropped the resource parameter, so only the
login_hint fast path could carry it, and nothing downstream ever set a
resource audience. Absent a resource indicator the prior behaviour stands:
EMULATE_WORKOS_AUDIENCE when set, else the requesting client.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant