Skip to content

RFC: Registry authentication for ToolHive CLI#43

Merged
ChrisJBurns merged 6 commits intomainfrom
rfc/registry-authentication
Mar 5, 2026
Merged

RFC: Registry authentication for ToolHive CLI#43
ChrisJBurns merged 6 commits intomainfrom
rfc/registry-authentication

Conversation

@ChrisJBurns
Copy link
Contributor

Summary

  • Add OAuth/OIDC authentication with PKCE for ToolHive CLI to access private MCP server registries
  • Phase 1: Browser-based OAuth flow with token caching and transparent refresh
  • Phase 2 (future): Static bearer token support for CI/CD environments

Test plan

  • Review RFC content for completeness and accuracy
  • Verify alignment with existing auth infrastructure (pkg/auth/oauth/, pkg/secrets/)
  • Validate security considerations cover all threat vectors
  • Confirm backward compatibility claims

Related: toolhive#2962, toolhive#3908

🤖 Generated with Claude Code

ChrisJBurns and others added 4 commits February 20, 2026 22:35
Add RFC for OAuth/OIDC authentication support when accessing remote
MCP server registries. Phase 1 covers browser-based OAuth with PKCE,
Phase 2 covers bearer tokens for CI/CD environments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix sequence diagram: auth.Transport calls Token(), not Registry
- Resolve callback port question: port 8666 shared intentionally
  (registry auth and remote MCP auth never run simultaneously)
- Document graceful degradation when secrets manager isn't set up
- Document get-registry output change (OAuth configured/authenticated)
- Clarify callback server timeout behavior in security mitigations
- Remove Testing Strategy section (tests pending in implementation)
- Remove ClientSecret field (not in scope for Phase 1)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changes based on review by OAuth/OIDC, ToolHive architecture, MCP protocol,
and Security expert panel:

OAuth/OIDC:
- Remove use_pkce toggle — PKCE with S256 is mandatory, not configurable
- Clarify audience vs RFC 8707 resource terminology
- Document state parameter crypto/rand generation
- Document refresh token rotation handling
- Enforce HTTPS for issuer URL (localhost exception)

ToolHive Architecture:
- Document thv serve limitation (browser flow incompatible with headless)
- Document RemoteRegistryProvider auth exclusion as explicit limitation
- Add actionable 401/403 error messages with remediation commands

MCP Protocol:
- Add MCP spec alignment note (registry-level vs server-level auth)
- Derive secret keys from registry URL hash to prevent token clobbering
- Add Alternative 6: RFC 9728 auto-discovery (deferred)

Security:
- Specify config file 0600 permissions (programmatic enforcement)
- Explicit 127.0.0.1 binding for callback server
- Add config file exposure to threat model
- Clarify --allow-private-ip scope and risks
- Specify 120-second browser flow timeout
- Add delimiter to hash input to prevent concatenation ambiguity
- Add Future Considerations section (token revocation, ephemeral ports)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Incorporate feedback from @reyortiz3, @JAORMX, and @peppescg:

- Switch from custom TokenSource interface to oauth2.TokenSource from
  golang.org/x/oauth2, aligning with the existing auth infrastructure
  and eliminating the need for adapter code
- Use standard oauth2.Transport instead of custom RoundTripper
- Clarify pkg/registry/auth/ separation rationale (thin orchestration
  layer composing from pkg/auth/ primitives, not re-implementing them)
- Add thv registry login/logout commands for explicit authentication
- Document MDM/enterprise pre-loaded config support
- Add auth status API (auth_status, auth_type fields) to thv serve
  registry endpoint for ToolHive Studio integration
- Add structured registry_auth_required JSON error from thv serve
- Add Studio-initiated async auth flow to Future Considerations
- Add config validation at load time to Future Considerations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
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.

great work, I just added a couple of comments but none is blocking. Happy to see PKCE used by default without opt-out.

Implementation Guide (for agent-based implementation):
- Constructor signatures for NewOAuthTokenSource
- Token() method orchestration pseudocode composing existing primitives
- Interactive flag threading through factory → provider → token source
- Secrets provider optional handling and graceful degradation
- oauth2.Transport wiring into HTTP client chain
- thv registry login/logout Cobra command structure
- API integration: auth status fields, structured 503 errors, 401
  detection, getCurrentProvider integration
- Security constraints: secret key derivation (h[:4]), sentinel error,
  token logging safety rules

Address @jhrozek review feedback:
- Add issuer-binding validation per OIDC Discovery §4.3 (MITM protection)
- Add OIDC discovery hijack to threat model and mitigations table
- Add per-IdP audience configuration table (Auth0, Okta, Azure AD, Keycloak)
- Clarify nonce not needed (ID tokens not consumed, only access/refresh)
- Fix logout to clear tokens only, not auth config (standard convention)
- Add thv registry login naming rationale (multiple auth contexts)
- Strengthen ephemeral ports note (Okta exact-match incompatibility)
- Add registry-served discovery document future consideration
- Add thv login alias future consideration
- Expand Studio POST /initiate with API contract and security controls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
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.

this is great and addresses all my comments. Small nit, the text addressed my logout comment, but the implementation guide still nukes the auth config.

@ChrisJBurns
Copy link
Contributor Author

@jhrozek I'm happy to merge this and submit a follow up PR just to reduce cognitive load of the entire PR

@ChrisJBurns ChrisJBurns merged commit 204e12d into main Mar 5, 2026
1 check 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.

7 participants