Skip to content

feat(op): support resource indicators (RFC 8707) at the authorization endpoint - #955

Open
amartya-dev wants to merge 1 commit into
zitadel:mainfrom
amartya-dev:feat/794-resource-indicators
Open

feat(op): support resource indicators (RFC 8707) at the authorization endpoint#955
amartya-dev wants to merge 1 commit into
zitadel:mainfrom
amartya-dev:feat/794-resource-indicators

Conversation

@amartya-dev

Copy link
Copy Markdown

Which Problems Are Solved

  • oidc.AuthRequest has no field for the resource parameter of RFC 8707 (Resource Indicators for OAuth 2.0), so the parameter is silently dropped at the authorization endpoint. A Storage implementation never learns which resource a token was requested for, and therefore cannot bind the audience of the issued token to it.
  • The only workaround today is to read resource out of the raw http.Request before it reaches op.Authorize and thread it into the audience by hand. That is easy to get subtly wrong — the failure mode is a token with a wildcard or default audience, which defeats the point of asking for a resource in the first place.
  • Nothing validates the syntax of resource values, and there is no way for an OP to advertise the capability in its discovery document.

The motivation is audience binding for MCP servers. MCP revision 2026-07-28 makes every MCP server an OAuth 2.1 resource server: the server MUST validate that a token's audience is itself, and the client MUST send the RFC 8707 resource parameter. Resource indicators are the mechanism that audience binding depends on.

How the Problems Are Solved

  • oidc.AuthRequest gains Resource []string with the resource schema tag, so repeated resource parameters are decoded at /authorize and reach Storage.CreateAuthRequest on the *oidc.AuthRequest that is already passed to it. An implementation can read the requested resources there and use them to determine the audience returned by AuthRequest.GetAudience(). No interface change is required, so this is fully backwards compatible — implementations that ignore the field keep their current behaviour.
  • op.ValidateAuthReqResources validates the values per RFC 8707, section 2: each value must be an absolute URI and must not include a fragment component. A query component is explicitly allowed, as the RFC permits. Invalid values are rejected with the invalid_target error code the RFC specifies (oidc.InvalidTarget already exists in the package for token exchange). The function is called from ValidateAuthRequestClient after the redirect URI has been validated, so the error can safely be returned to the client.
  • Only the syntax is validated in the library. Whether a resource is acceptable for a given client, and how it maps onto the token audience, stays with the Storage implementation — that policy cannot live in the library.
  • CopyRequestObjectToAuthRequest copies Resource from a Request Object, consistent with how every other authorization parameter is handled there.
  • oidc.DiscoveryConfiguration gains ResourceIndicatorsSupported (resource_indicators_supported, omitempty), driven by a new op.Config.ResourceIndicatorsSupported field via the op.ResourceIndicatorsSupported(Configuration) helper. This follows the existing op.Scopes(Configuration) / Config.SupportedScopes pattern, so it is an additive field on the Config struct rather than a new method on the Configuration interface. It defaults to false and is omitted from the discovery document, so nothing changes for existing providers until they opt in.

Tests are added in the existing table-driven style: TestValidateAuthReqResources, TestCopyRequestObjectToAuthRequest, Test_ResourceIndicatorsSupported, plus new cases in TestParseAuthorizeRequest, TestValidateAuthRequest and TestDiscover.

Additional Changes

  • Behaviour note: an authorization request that carries a syntactically invalid resource value is now rejected with invalid_target where it was previously ignored. This is what the RFC requires, but it is a change in behaviour for a provider whose clients currently send malformed values. If you would rather have this gated behind Config.ResourceIndicatorsSupported as well, I am happy to change it.
  • resource_indicators_supported is not an IANA-registered authorization server metadata parameter — RFC 8707 does not define one. It is the name used by convention to advertise the capability, and this is noted in the field's doc comment. Happy to drop it if you would prefer not to emit an unregistered parameter.

Deliberately Out of Scope

Kept out to keep this reviewable; happy to follow up on any of them:

  • The resource parameter at the token endpoint (RFC 8707, section 2.2) for down-scoping the audience on code exchange and refresh. This PR covers the authorization endpoint only.
  • The device authorization endpoint.
  • A dedicated rp.WithResourceURLParam option on the relying party side. rp.WithURLParam already covers the single-resource case; a repeated-parameter option needs a small change to withURLParam.
  • Changes to the example server storage. The example keeps its current audience behaviour rather than growing a resource-to-audience policy.

Additional Context

I am aware of #785 and that feature reviews are constrained at the moment — no rush at all on this one. It is written to be small and additive so it is cheap to review whenever there is time.

… endpoint

The `resource` parameter was silently dropped at the authorization
endpoint, so a Storage implementation had no way to learn which resource
a token was requested for and could not bind the token audience to it.

Add `Resource` to `oidc.AuthRequest` so the parameter is parsed and
handed to `Storage.CreateAuthRequest`, validate the values per RFC 8707
section 2 (absolute URI, no fragment) and reject invalid ones with
`invalid_target`, copy the values from a Request Object like the other
authorization parameters, and let an OP advertise
`resource_indicators_supported` in its discovery document through the
new `Config.ResourceIndicatorsSupported` option.
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.

Support of RFC-8707

1 participant