Skip to content

fix(sdk): resend the OAuth resource on token refresh - #19

Merged
quantumdark merged 1 commit into
developmentfrom
fix/oauth-refresh-resource
Sep 11, 2026
Merged

fix(sdk): resend the OAuth resource on token refresh#19
quantumdark merged 1 commit into
developmentfrom
fix/oauth-refresh-resource

Conversation

@quantumdark

@quantumdark quantumdark commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • OAuthCredential gains an optional resource field (RFC 8707), filled in by exchange_code and persisted to the config file.
  • refresh / refresh_async pass resource=credential.resource to authlib's refresh_token, so it lands in the form body. Omitted when None.
  • Credentials stored by 0.3.x have no resource; they load with None and refresh exactly as before until the next discolike auth login.
  • CLI unchanged: it already passes base_url as the resource into exchange_code.

Why

Refreshes went to the token endpoint without resource. We are about to enable PropelAuth's MCP default resource (project-wide, pointed at the MCP audience). If PropelAuth applies that default to resource-less refresh_token grants, every refreshed REST token would come back with the MCP aud and be rejected by the REST API. Sending resource on refresh is spec-correct regardless of how PropelAuth answers.

Test plan

  • New tests: exchange stores resource; sync and async refresh send it and keep it on the rotated credential; config round-trip includes it; legacy config without it loads as None.
  • Existing refresh tests (no resource) still assert the form has no resource key.
  • Full suite: 572 passed. ruff check and ruff format --check clean.
  • After release: discolike auth login against dev, wait for a refresh, confirm REST still 200 with default resource enabled.

Greptile Summary

This PR preserves the RFC 8707 resource associated with an OAuth credential and resends it during synchronous and asynchronous token refreshes.

  • Adds an optional, backward-compatible resource field to persisted OAuth credentials.
  • Carries the resource from authorization-code exchange through token rotation.
  • Omits the refresh parameter for legacy credentials that do not contain a resource.
  • Adds request-contract, rotation, configuration-roundtrip, and legacy-configuration coverage.

Confidence Score: 5/5

The PR appears safe to merge; the OAuth resource is preserved through configuration and token rotation without changing legacy refresh requests.

All affected login, persistence, synchronous refresh, asynchronous refresh, and request-triggered refresh paths retain the resource, while credentials lacking it continue to omit the parameter as intended.

Important Files Changed

Filename Overview
packages/discolike/src/discolike/_credentials.py Adds backward-compatible parsing and serialization of the optional OAuth resource.
packages/discolike/src/discolike/_oauth.py Resends non-empty resources during sync and async refresh and preserves them across token rotation.
packages/discolike/tests/test_config.py Covers resource persistence and loading credentials written before the field existed.
packages/discolike/tests/test_oauth.py Verifies exchange, synchronous refresh, and asynchronous refresh resource behavior.

Reviews (1): Last reviewed commit: "fix(sdk): resend the OAuth resource on t..." | Re-trigger Greptile

Context used (3)

Refreshes went to the token endpoint without the RFC 8707 resource, so an
authorization server that applies a default resource to resource-less
requests could re-bind the refreshed REST token to another audience.
OAuthCredential now carries the resource from the code exchange, persists
it, and passes it to authlib's refresh_token. Credentials stored before
this release have no resource and keep the previous behavior.
@quantumdark
quantumdark merged commit 60da6e0 into development Sep 11, 2026
8 checks passed
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