Skip to content

Add --remote-auth-scope-param-name for non-standard OAuth scope parameters#4712

Merged
peppescg merged 3 commits intostacklok:mainfrom
gmogmzGithub:fix/slack-oauth-user-scope
Apr 14, 2026
Merged

Add --remote-auth-scope-param-name for non-standard OAuth scope parameters#4712
peppescg merged 3 commits intostacklok:mainfrom
gmogmzGithub:fix/slack-oauth-user-scope

Conversation

@gmogmzGithub
Copy link
Copy Markdown
Contributor

@gmogmzGithub gmogmzGithub commented Apr 9, 2026

Summary

  • Adds --remote-auth-scope-param-name CLI flag to override the query parameter name used for scopes in the OAuth authorization URL
  • When set (e.g., user_scope), scopes are sent under the custom parameter name and the standard scope= is cleared
  • oauth2Config.Scopes is preserved so token refresh continues to work correctly

Motivation

Slack's OAuth v2 requires user-token scopes in user_scope= instead of the standard scope= parameter. When ToolHive connects to https://mcp.slack.com/mcp, its OAuth discovery correctly finds the v2_user/authorize endpoint and the 15 supported scopes, but Go's oauth2 library always places scopes in scope=. Slack rejects this with invalid_scope.

This flag closes the gap so ToolHive can authenticate with providers that use non-standard scope parameter names.

Example usage for Slack MCP

thv run https://mcp.slack.com/mcp \
  --name slack \
  --transport streamable-http \
  --remote-auth-client-id 1601185624273.8899143856786 \
  --remote-auth-callback-port 3118 \
  --remote-auth-authorize-url "https://slack.com/oauth/v2_user/authorize" \
  --remote-auth-token-url "https://slack.com/api/oauth.v2.user.access" \
  --remote-auth-scope-param-name user_scope

Changes

File Change
pkg/auth/oauth/flow.go ScopeParamName field on Config; buildAuthURL override logic
pkg/auth/oauth/manual.go Pass-through scopeParamName parameter
pkg/auth/discovery/discovery.go ScopeParamName on OAuthFlowConfig
pkg/auth/remote/config.go ScopeParamName field with JSON/YAML tags
pkg/auth/remote/handler.go Wire ScopeParamName to flow config
cmd/thv/app/auth_flags.go New --remote-auth-scope-param-name flag
cmd/thv/app/run_flags.go Wire through both config builders
cmd/thv/app/proxy.go Wire through both flow configs

@gmogmzGithub gmogmzGithub force-pushed the fix/slack-oauth-user-scope branch from 1feeca8 to 141b5cf Compare April 9, 2026 18:55
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 10, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 10, 2026

Codecov Report

❌ Patch coverage is 60.00000% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.99%. Comparing base (be40131) to head (4782cd3).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
pkg/auth/remote/handler.go 0.00% 11 Missing ⚠️
pkg/auth/discovery/discovery.go 50.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4712      +/-   ##
==========================================
+ Coverage   68.98%   68.99%   +0.01%     
==========================================
  Files         518      518              
  Lines       54985    55000      +15     
==========================================
+ Hits        37932    37949      +17     
+ Misses      14125    14124       -1     
+ Partials     2928     2927       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gmogmzGithub gmogmzGithub force-pushed the fix/slack-oauth-user-scope branch 3 times, most recently from 6506bb2 to 849326a Compare April 12, 2026 22:25
Copy link
Copy Markdown
Contributor

@jhrozek jhrozek left a comment

Choose a reason for hiding this comment

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

Review from 4 specialized agents (oauth-expert, go-security-reviewer, code-reviewer, go-expert-developer). 3 inline comments.

Comment thread pkg/auth/oauth/flow.go Outdated
Comment thread pkg/auth/discovery/discovery.go
Comment thread cmd/thv/app/proxy.go
Copy link
Copy Markdown
Contributor

@jhrozek jhrozek left a comment

Choose a reason for hiding this comment

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

Looks good — all the substantive feedback has been addressed cleanly. The nil-out-and-restore approach for scope removal is correct, and the OIDC discovery path now properly propagates ScopeParamName.

Generated with Claude Code

@gmogmzGithub gmogmzGithub force-pushed the fix/slack-oauth-user-scope branch from ff67ef5 to 41ba489 Compare April 14, 2026 14:37
jhrozek
jhrozek previously approved these changes Apr 14, 2026
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 14, 2026
…parameters

Some OAuth providers use non-standard query parameter names for scopes
in the authorization URL. For example, Slack's OAuth v2 requires
user-token scopes in "user_scope" instead of the standard "scope"
parameter. This causes ToolHive's OAuth flow to fail with invalid_scope
errors when connecting to providers like Slack's MCP server.

Add a new --remote-auth-scope-param-name flag that allows users to
override the query parameter name used for scopes. When set, scopes are
sent under the specified parameter name and the standard "scope"
parameter is cleared. The oauth2Config.Scopes field is preserved so
token refresh requests continue to work correctly.

Signed-off-by: Gustavo Gomez <gmogmz@indeed.com>
- Replace SetAuthURLParam("scope", "") with temporarily nil-ing
  oauth2Config.Scopes before AuthCodeURL, then restoring via defer.
  This omits the scope parameter entirely instead of producing an
  invalid empty scope= (RFC 6749 §3.3).
- Propagate ScopeParamName on the OIDC discovery fallback path in
  createOAuthConfig, so --remote-auth-scope-param-name works with
  --remote-auth-issuer as well.
- Strengthen test assertion to verify scope parameter is truly absent,
  not just empty-valued.

Signed-off-by: Gustavo Gomez <gmogmz@indeed.com>
Signed-off-by: Gustavo Gomez <gmogmz@indeed.com>
@gmogmzGithub gmogmzGithub force-pushed the fix/slack-oauth-user-scope branch from ccc4b92 to 4782cd3 Compare April 14, 2026 15:24
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 14, 2026
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 14, 2026
@peppescg peppescg merged commit b250b90 into stacklok:main Apr 14, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/S Small PR: 100-299 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants