Skip to content

fix(mcp): request offline access so OAuth servers issue refresh tokens - #59821

Open
aNewMoose wants to merge 2 commits into
anomalyco:devfrom
aNewMoose:fix/mcp-oauth-offline-access
Open

aNewMoose wants to merge 2 commits into
anomalyco:devfrom
aNewMoose:fix/mcp-oauth-offline-access

Conversation

@aNewMoose

@aNewMoose aNewMoose commented Oct 28, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #59820

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

The MCP OAuth authorization URL never asked for offline access, so Google's authorization server returned only a ~1-hour access token and no refresh token — an hour after each sign-in every request 401s and the server reports "requires user authorization" (log shows mcp oauth authorization completed ... hasRefreshToken=false expiresIn=3599). This sets access_type=offline on the authorization URL at the single point where OpenCode hands it to the browser (redirectToAuthorization in packages/core/src/mcp/oauth.ts), covering initial login and re-authorization. RFC 6749 §3.1 requires authorization servers to ignore unrecognized request parameters, so servers that already issue refresh tokens (Linear, Sentry, etc.) are unaffected. prompt=consent is deliberately not sent, so consent prompting behavior is unchanged.

How did you verify your code works?

  • cd packages/core && bun run test test/mcp-oauth.test.ts — 23 pass, 0 fail (new test included).
  • cd packages/core && bun typecheck — no type errors; root bun run lint — 0 errors.
  • Full cd packages/core && bun run test — 6903 pass, 8 fail; those 8 (shell-syntax and git-utility tests) fail identically on unmodified dev and are unrelated to this change.
  • The new test fails with the change reverted and passes with it. The existing requests offline_access without forcing a consent prompt test guards that no prompt parameter is added.

To verify by hand: sign in to a Google OAuth-backed MCP server (e.g. the Gmail MCP server), check the authorization URL in the browser contains access_type=offline, then that the log shows hasRefreshToken=true and later operation=refresh instead of hourly 401s.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Added by the opencode bot (AI-generated).

Related: #58319, #49773

The MCP OAuth authorization URL never asked for offline access, so
Google-style authorization servers returned only a ~1-hour access token
and no refresh token, and every request 401ed an hour after sign-in with
"requires user authorization". Set access_type=offline on the
authorization URL at the single funnel where OpenCode hands it to the
browser. RFC 6749 §3.1 requires authorization servers to ignore
unrecognized request parameters, so servers that already issue refresh
tokens are unaffected. No prompt=consent is sent.
@aNewMoose
aNewMoose marked this pull request as ready for review October 28, 2026 04:46

@opencodejr opencodejr Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks good to me. I ran the #59820 reproduction (a mock OAuth MCP server that issues no refresh token, then opencode mcp auth gmail from source) on both checkouts. On the base branch the authorization URL has no access_type. With this PR it carries access_type=offline and sign-in still completes. test/mcp-oauth.test.ts passes (23/23), and tsc --noEmit in packages/core is clean.

Public API: unchanged. The only behaviour change is one extra query parameter on the MCP OAuth authorization URL.

No blocking concerns. One thing users may notice: Google usually returns a refresh token only on first consent. Without prompt=consent, which #50519 deliberately removed, accounts that already granted access may still get no refresh token until they revoke access and sign in again.

Related: #58319, #49773

@opencodejr opencodejr Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The new commit only merges dev; the fix and its test haven't changed. I re-ran the #59820 reproduction on the new head: the authorization URL still carries access_type=offline and sign-in completes. test/mcp-oauth.test.ts passes (23/23). Public API: unchanged. No new concerns.

This branch has not been deployed

No deployments
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.

mcp: OAuth authorization never requests offline access, so Google issues no refresh token

1 participant