Skip to content

fix: enable silent token refresh in proxy mode#32

Closed
caiopavanelli wants to merge 2 commits into
tuannvm:mainfrom
caiopavanelli:fix/offline-access-proxy-mode
Closed

fix: enable silent token refresh in proxy mode#32
caiopavanelli wants to merge 2 commits into
tuannvm:mainfrom
caiopavanelli:fix/offline-access-proxy-mode

Conversation

@caiopavanelli
Copy link
Copy Markdown

@caiopavanelli caiopavanelli commented May 22, 2026

Problem

Claude Desktop (and other MCP clients) require silent token renewal to avoid forcing users to re-authenticate every hour when the access token expires.

Two bugs prevented this from working in proxy mode:

1. grant_types_supported missing refresh_token in discovery documents

GetAuthorizationServerMetadata() and HandleOIDCDiscovery() only listed authorization_code. Per RFC 8414, a conformant client will not attempt silent renewal if refresh_token is absent — it will fall back to a full re-auth. Notably, HandleRegister() already returned both grant types correctly; this brings the discovery endpoints in line.

2. offline_access scope not requested from upstream provider

Most OIDC providers (Okta, Azure AD, etc.) only issue a refresh token when offline_access is explicitly present in the scope list. The existing oauth2.AccessTypeOffline option only appends access_type=offline to the authorization URL, which is recognised by Google but silently ignored by Okta/Azure. Without offline_access in the scopes, the upstream provider never issues a refresh token, so there is nothing for the client to renew with.

Changes

metadata.go

Add "refresh_token" to grant_types_supported in GetAuthorizationServerMetadata() (both native and proxy mode branches) and HandleOIDCDiscovery().

handlers.go

In NewOAuth2ConfigFromConfig, when mode == "proxy", automatically append "offline_access" to the scope list if not already present. The guard is idempotent — callers who already include offline_access in their configured scopes are unaffected.

Testing

  • All existing tests pass (go test ./...)
  • Both fixes are required: the metadata fix tells clients to attempt renewal; the scope fix ensures the upstream provider actually issues a refresh token to renew with.

Summary by CodeRabbit

New Features

  • Added "offline_access" scope support in OAuth/OIDC proxy mode configuration
  • Updated OAuth/OIDC metadata and discovery endpoints to advertise refresh_token grant type support

Review Change Stack

In proxy mode, automatically append offline_access to the OAuth scope
list when it is not already present.

Most OIDC providers (Okta, Azure AD, etc.) only issue a refresh token
when offline_access is explicitly requested as a scope. The existing
oauth2.AccessTypeOffline option only appends access_type=offline to the
authorization URL, which is honoured by Google but ignored by the rest.

Without a refresh token, clients such as Claude Desktop cannot silently
renew credentials and must prompt the user to re-authenticate every time
the access token expires (~1 h).

The guard is idempotent: callers who already include offline_access in
their configured scope list are unaffected.
Add refresh_token to grant_types_supported in GetAuthorizationServerMetadata
(both native and proxy mode branches) and HandleOIDCDiscovery.

The /oauth/token handler already supports the refresh_token grant type,
but the discovery documents were only listing authorization_code.
Per RFC 8414 a conformant client will not attempt silent token renewal
if refresh_token is absent from grant_types_supported, causing it to
force a full re-authentication every time the access token expires.

HandleRegister already returned both grant types correctly; this brings
the discovery endpoints in line with that and with the actual behaviour
of the token endpoint.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8286d65a-536d-458e-b892-3d4cec9d4b05

📥 Commits

Reviewing files that changed from the base of the PR and between ba543d8 and 33883fe.

📒 Files selected for processing (2)
  • handlers.go
  • metadata.go

Walkthrough

This PR enables OAuth2 refresh token support by ensuring proxy mode includes the "offline_access" scope during configuration, and updates all metadata endpoints to advertise refresh_token as a supported grant type.

Changes

OAuth2 Refresh Token Support

Layer / File(s) Summary
Enable offline_access scope in proxy mode
handlers.go
NewOAuth2ConfigFromConfig now scans the computed scopes list in proxy mode and appends "offline_access" if missing, ensuring upstream OIDC providers can issue refresh tokens.
Advertise refresh_token grant type in metadata
metadata.go
HandleOIDCDiscovery, GetAuthorizationServerMetadata (native), and GetAuthorizationServerMetadata (proxy) now list refresh_token alongside authorization_code in grant_types_supported.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • tuannvm/oauth-mcp-proxy#17: Adds HandleToken endpoint support for the refresh_token grant flow, directly complementing this PR's addition of offline scope configuration and refresh token grant type advertisement.

Poem

🐰 With tokens that dance and scopes that stay true,
A rabbit hops forth with offline_access anew,
The refresh token grant spreads across every door,
Now OIDC providers can give tokens galore!
Long-lived sessions, at last!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: enable silent token refresh in proxy mode' directly and clearly summarizes the main objective of the changeset—enabling silent token refresh in proxy mode by adding offline_access scope and refresh_token grant type support.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@caiopavanelli caiopavanelli deleted the fix/offline-access-proxy-mode branch June 2, 2026 13:58
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