Repository navigation
Conversation
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Issue for this PR
Closes #59820
Type of change
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 setsaccess_type=offlineon the authorization URL at the single point where OpenCode hands it to the browser (redirectToAuthorizationinpackages/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=consentis 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; rootbun run lint— 0 errors.cd packages/core && bun run test— 6903 pass, 8 fail; those 8 (shell-syntax and git-utility tests) fail identically on unmodifieddevand are unrelated to this change.requests offline_access without forcing a consent prompttest guards that nopromptparameter 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 showshasRefreshToken=trueand lateroperation=refreshinstead of hourly 401s.Checklist
Added by the opencode bot (AI-generated).
Related: #58319, #49773