Skip to content

Conversation

@craigds
Copy link

@craigds craigds commented Dec 8, 2025

Fixes #1102

Description of the Change

oauth server changes:

  • Add resource field to Grant and AccessToken models (migrations included)
  • Accept & validate resource parameter in authorization/token requests
  • token view: reject unauthorized resources with invalid_target error

token validation changes (resource server):

  • Add validate_resource_as_url_prefix() with URL prefix matching logic
  • New setting: RESOURCE_SERVER_TOKEN_RESOURCE_VALIDATOR (pluggable)
  • Use the validator function in validate_bearer_token() when the token has an audience claim

Checklist

  • PR only contains one change (considered splitting up PR) arguable, but I think these two commits belong together
  • unit-test added
  • documentation updated
  • CHANGELOG.md updated (only for user relevant changes)
  • author name in AUTHORS
  • tests/app/idp updated to demonstrate new features
  • tests/app/rp updated to demonstrate new features

Copilot AI review requested due to automatic review settings December 8, 2025 23:59
# connect to the django-oauth-toolkit package in the parent workspace
# so changes to it are reflected here without reinstalling.
django-oauth-toolkit = { editable = true, workspace = true }
django-oauth-toolkit = { workspace = true }
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, this isn't directly related obviously. I was unable to even get this app to work at all without this change:

$ uv run tox
error: Failed to parse: `tests/app/idp/pyproject.toml`
  Caused by: TOML parse error at line 22, column 24
   |
22 | django-oauth-toolkit = { editable = true, workspace = true }
   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cannot specify both `workspace` and `editable`

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements RFC 8707 "Resource Indicators" support, allowing clients to bind OAuth 2.0 access tokens to specific resource servers. This enhances security by preventing tokens from being misused at unintended services.

Key changes:

  • Added resource field to Grant and AccessToken models to store resource indicators as JSON-encoded arrays of URIs
  • Authorization and token endpoints now accept and validate the resource parameter
  • Token introspection endpoint returns the aud (audience) claim for tokens with resource binding
  • Automatic audience validation in bearer token validation using configurable validator functions
  • New setting RESOURCE_SERVER_TOKEN_RESOURCE_VALIDATOR with default URL prefix-based matching

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
oauth2_provider/models.py Added resource field to AbstractGrant and AbstractAccessToken models; implemented get_audiences() and allows_audience() methods for RFC 8707 support
oauth2_provider/oauth2_validators.py Added validate_resource_as_url_prefix() function; integrated resource extraction and validation in token creation/validation flows; added resource escalation prevention
oauth2_provider/views/base.py Modified authorization view to extract and JSON-encode resource parameter(s) from requests
oauth2_provider/views/introspect.py Added aud field to introspection response when token has resource binding
oauth2_provider/forms.py Added resource hidden field to AllowForm
oauth2_provider/settings.py Added RESOURCE_SERVER_TOKEN_RESOURCE_VALIDATOR setting with default validator
oauth2_provider/migrations/0014_grant_resource.py Migration to add resource field to Grant model
oauth2_provider/migrations/0015_accesstoken_resource.py Migration to add resource field to AccessToken model
tests/test_rfc8707_integration.py Comprehensive integration tests for RFC 8707 flows (authorization code, client credentials, implicit)
tests/test_resource_validators.py Unit tests for URL prefix validator and integration tests for bearer token validation
tests/test_models.py Tests for AccessToken.get_audiences() method
tests/test_introspection_view.py Tests for aud field in introspection responses
tests/test_authorization_code.py Tests for resource parameter in authorization code flow
docs/settings.rst Documentation for new RESOURCE_SERVER_TOKEN_RESOURCE_VALIDATOR setting
docs/resource_server.rst Comprehensive documentation on RFC 8707 token audience binding and validation
docs/getting_started.rst Added note about optional resource parameter for binding tokens
CHANGELOG.md Added RFC 8707 support to changelog
tests/app/idp/pyproject.toml Removed editable flag from workspace dependency

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Fixes django-oauth#1102

Implement RFC 8707 to bind access tokens to specific resource servers:
- Add resource field to Grant and AccessToken models (migrations
  included)
- Accept & validate resource parameter in authorization/token requests
- token view: reject unauthorized resources with `invalid_target` error

This change is backward compatible - clients not providing a `resource`
in the request will receive a token providing unrestricted access, as
before.
This validates the token audience (if there is one) against the request
URI.

Specs are unclear on *exactly* how this validation should be done.

Most implementations seem to require an *exact* match between the token
`aud` and the resource server identifier (Auth0, Okta, AWS Cognito)

This is a pain because it requires some extra configuration on the
resource server to define what exactly is 'the resource server identifier'
 - is it the host name, a hardcoded identifier or some subresource path?

I have opted for a pluggable system so the project can define what
approach to use, but I've chosen a default approach which I hope is
more flexible and requires no configuration - we match the token
audience claim to the request using a url prefix.

i.e. when requesting `https://example.com/users/foo`, a token with
`aud: ["https://example.com/users"]` would match.

This approach is implemented by Ory Hydra:
https://www.ory.com/docs/hydra/guides/audiences#audience-in-authorization-code-implicit-and-hybrid-flows

I also found a ticket requesting this feature for Ory Oathkeeper:
ory/oathkeeper#656

Changes:
- Add `validate_resource_as_url_prefix()` with URL prefix matching logic
- New setting: `RESOURCE_SERVER_TOKEN_RESOURCE_VALIDATOR` (pluggable)
- Use the validator function in `validate_bearer_token()` when the token
  has an audience claim
@craigds craigds force-pushed the rfc8707-resource-indicators branch from 7fbbeac to 5eb1b67 Compare December 9, 2025 01:22
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.

RFC 8707 Resource indicators

1 participant