Documentation
¶
Overview ¶
Package remote provides authentication handling for remote MCP servers.
This package implements OAuth/OIDC-based authentication with automatic discovery support for remote MCP servers. It handles:
- OAuth issuer discovery (RFC 8414)
- Protected resource metadata (RFC 9728)
- OAuth flow execution (PKCE-based)
- Token source creation for HTTP transports
The main entry point is Handler.Authenticate() which takes a remote URL and performs all necessary discovery and authentication steps.
Configuration is defined in pkg/runner.RemoteAuthConfig as part of the runner's RunConfig structure.
Index ¶
- Constants
- func CreateTokenSourceFromCached(config *oauth2.Config, refreshToken string, expiry time.Time, resource string, ...) (oauth2.TokenSource, error)
- func DefaultResourceIndicator(remoteServerURL string) string
- type BearerTokenSource
- type ClientCredentialsPersister
- type Config
- func (c *Config) ClearCachedClientCredentials()
- func (c *Config) ClearCachedTokens()
- func (c *Config) HasCachedCIMDClientID() bool
- func (c *Config) HasCachedClientCredentials() bool
- func (c *Config) HasValidCachedTokens() bool
- func (c *Config) LogContext() (upstream, clientID string)
- func (r *Config) UnmarshalJSON(data []byte) error
- type Handler
- func (h *Handler) Authenticate(ctx context.Context, remoteURL string) (oauth2.TokenSource, error)
- func (h *Handler) SetClientCredentialsPersister(persister ClientCredentialsPersister)
- func (h *Handler) SetHTTPClient(client networking.HTTPClient)
- func (h *Handler) SetSecretProvider(provider secrets.Provider)
- func (h *Handler) SetTokenPersister(persister TokenPersister)
- type PersistingTokenSource
- type TokenPersister
Constants ¶
const BearerTokenEnvVarName = "TOOLHIVE_REMOTE_AUTH_BEARER_TOKEN"
BearerTokenEnvVarName is the environment variable name used for bearer token authentication. The bearer token will be read from this environment variable if not provided via flag or file. #nosec G101 - this is an environment variable name, not a credential
const DefaultCallbackPort = 8666
DefaultCallbackPort is the default port for the OAuth callback server
Variables ¶
This section is empty.
Functions ¶
func CreateTokenSourceFromCached ¶ added in v0.8.1
func CreateTokenSourceFromCached( config *oauth2.Config, refreshToken string, expiry time.Time, resource string, trusted bool, ) (oauth2.TokenSource, error)
CreateTokenSourceFromCached creates an oauth2.TokenSource from a cached refresh token. The returned token source will immediately refresh to get a new access token, then automatically refresh when it expires. If resource is non-empty, it is included in all refresh requests per RFC 8707. trusted reports that the token endpoint's authority came from operator configuration; see oauth.Config.TokenEndpointTrusted.
func DefaultResourceIndicator ¶
DefaultResourceIndicator derives the resource indicator (RFC 8707) from the remote server URL. This function should only be called when the user has not explicitly provided a resource indicator. If the resource indicator cannot be derived, it returns an empty string.
Types ¶
type BearerTokenSource ¶ added in v0.6.17
type BearerTokenSource struct {
// contains filtered or unexported fields
}
BearerTokenSource implements oauth2.TokenSource for static bearer tokens. It returns a token with the bearer token value as the access token.
func NewBearerTokenSource ¶ added in v0.6.17
func NewBearerTokenSource(bearerToken string) *BearerTokenSource
NewBearerTokenSource creates a new BearerTokenSource with the provided bearer token.
type ClientCredentialsPersister ¶ added in v0.9.0
type ClientCredentialsPersister func( clientID string, clientSecret string, secretExpiry time.Time, registrationAccessToken string, registrationClientURI string, tokenEndpointAuthMethod string, registeredCallbackPort int, ) error
ClientCredentialsPersister is called when DCR client credentials need to be persisted. This is used to store client_id, client_secret, and renewal metadata obtained during Dynamic Client Registration (RFC 7591) and needed for secret renewal (RFC 7592).
Parameters:
- clientID: the registered client ID (public, stored as plain text)
- clientSecret: the registered client secret (sensitive, stored via secret manager)
- secretExpiry: when the client secret expires; zero value means it never expires
- registrationAccessToken: bearer token for RFC 7592 management operations (sensitive)
- registrationClientURI: endpoint for RFC 7592 client update/read operations (plain text)
- tokenEndpointAuthMethod: the auth method used for the token endpoint (e.g., "client_secret_basic", "none")
- registeredCallbackPort: the callback port used in the original DCR redirect URI
type Config ¶
type Config struct {
ClientID string `json:"client_id,omitempty" yaml:"client_id,omitempty"`
ClientSecret string `json:"client_secret,omitempty" yaml:"client_secret,omitempty"` //nolint:gosec // G117
ClientSecretFile string `json:"client_secret_file,omitempty" yaml:"client_secret_file,omitempty"`
Scopes []string `json:"scopes,omitempty" yaml:"scopes,omitempty"`
SkipBrowser bool `json:"skip_browser,omitempty" yaml:"skip_browser,omitempty"`
Timeout time.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty" swaggertype:"string" example:"5m"`
CallbackPort int `json:"callback_port,omitempty" yaml:"callback_port,omitempty"`
UsePKCE bool `json:"use_pkce" yaml:"use_pkce"`
// Resource is the OAuth 2.0 resource indicator (RFC 8707).
Resource string `json:"resource,omitempty" yaml:"resource,omitempty"`
// OAuth endpoint configuration (from registry)
Issuer string `json:"issuer,omitempty" yaml:"issuer,omitempty"`
AuthorizeURL string `json:"authorize_url,omitempty" yaml:"authorize_url,omitempty"`
TokenURL string `json:"token_url,omitempty" yaml:"token_url,omitempty"`
// Headers for HTTP requests
Headers []*registry.Header `json:"headers,omitempty" yaml:"headers,omitempty" swaggerignore:"true"`
// Environment variables for the client
EnvVars []*registry.EnvVar `json:"env_vars,omitempty" yaml:"env_vars,omitempty" swaggerignore:"true"`
// OAuth parameters for server-specific customization
OAuthParams map[string]string `json:"oauth_params,omitempty" yaml:"oauth_params,omitempty"`
// ScopeParamName overrides the query parameter name used to send scopes in the
// authorization URL. When empty, the standard "scope" parameter is used.
// Some providers require a non-standard name (e.g., Slack uses "user_scope").
ScopeParamName string `json:"scope_param_name,omitempty" yaml:"scope_param_name,omitempty"`
// Bearer token configuration (alternative to OAuth)
BearerToken string `json:"bearer_token,omitempty" yaml:"bearer_token,omitempty"` //nolint:gosec // G117
BearerTokenFile string `json:"bearer_token_file,omitempty" yaml:"bearer_token_file,omitempty"`
// Cached OAuth token reference for persistence across restarts.
// The refresh token is stored securely in the secret manager, and this field
// contains the reference to retrieve it (e.g., "OAUTH_REFRESH_TOKEN_workload").
// This enables session restoration without requiring a new browser-based login.
CachedRefreshTokenRef string `json:"cached_refresh_token_ref,omitempty" yaml:"cached_refresh_token_ref,omitempty"`
CachedTokenExpiry time.Time `json:"cached_token_expiry,omitempty" yaml:"cached_token_expiry,omitempty"`
// Cached DCR client credentials for persistence across restarts.
// These are obtained during Dynamic Client Registration and needed to refresh tokens.
// ClientID is stored as plain text since it's public information.
CachedClientID string `json:"cached_client_id,omitempty" yaml:"cached_client_id,omitempty"`
CachedClientSecretRef string `json:"cached_client_secret_ref,omitempty" yaml:"cached_client_secret_ref,omitempty"`
// ClientSecretExpiresAt indicates when the client secret expires (if provided by the DCR server).
// A zero value means the secret does not expire.
CachedSecretExpiry time.Time `json:"cached_secret_expiry,omitempty" yaml:"cached_secret_expiry,omitempty"`
// CachedRegTokenRef is a secret manager reference to the registration_access_token
// returned in the DCR response. Used for RFC 7592 client update operations.
// Stored as a secret reference since it's sensitive.
CachedRegTokenRef string `json:"cached_reg_token_ref,omitempty" yaml:"cached_reg_token_ref,omitempty"`
// CachedCIMDClientID stores the CIMD metadata URL used as client_id when CIMD
// authentication was used. Kept separate from CachedClientID (which holds
// DCR-issued IDs) so the two can have independent lifecycles — DCR credential
// rotation clears CachedClientID without touching the stable CIMD URL.
// Read by resolveClientCredentials to send the correct client_id on token refresh.
CachedCIMDClientID string `json:"cached_cimd_client_id,omitempty" yaml:"cached_cimd_client_id,omitempty"`
// CachedRegClientURI is the registration_client_uri from the DCR response.
// This is the endpoint used for RFC 7592 client read/update/delete operations.
// Stored as plain text since it is not sensitive.
CachedRegClientURI string `json:"cached_reg_client_uri,omitempty" yaml:"cached_reg_client_uri,omitempty"`
// CachedTokenEndpointAuthMethod is the auth method used for the token endpoint
// (e.g., "client_secret_basic", "none"). Persisted for RFC 7592 updates.
CachedTokenEndpointAuthMethod string `json:"cached_token_auth_method,omitempty" yaml:"cached_token_auth_method,omitempty"`
// CachedDCRCallbackPort is the callback port that was actually registered
// during DCR. It may differ from CallbackPort when the requested port was
// unavailable and a fallback port was selected.
CachedDCRCallbackPort int `json:"cached_dcr_callback_port,omitempty" yaml:"cached_dcr_callback_port,omitempty"`
}
Config holds authentication configuration for remote MCP servers. Supports OAuth/OIDC-based authentication with automatic discovery.
func (*Config) ClearCachedClientCredentials ¶ added in v0.9.0
func (c *Config) ClearCachedClientCredentials()
ClearCachedClientCredentials removes any cached DCR client credential references from the config. It does not clear CachedCIMDClientID — the CIMD URL is a stable constant that does not need to be rotated alongside DCR secrets.
func (*Config) ClearCachedTokens ¶ added in v0.8.1
func (c *Config) ClearCachedTokens()
ClearCachedTokens removes any cached OAuth token references from the config. Note: This does not delete the actual secret from the secret manager.
func (*Config) HasCachedCIMDClientID ¶ added in v0.27.0
HasCachedCIMDClientID returns true if a CIMD client_id was cached from a prior session.
func (*Config) HasCachedClientCredentials ¶ added in v0.9.0
HasCachedClientCredentials returns true if the config has cached DCR client credentials.
func (*Config) HasValidCachedTokens ¶ added in v0.8.1
HasValidCachedTokens returns true if the config has a cached token reference that can be used to create a TokenSource without requiring a new OAuth flow. Note: This only checks if a refresh token reference exists, not if the token is actually valid. The actual validity will be determined when the token is used.
func (*Config) LogContext ¶ added in v0.27.0
LogContext returns the upstream issuer and resolved client_id for use as log-correlation fields on the MonitoredTokenSource. Returns ("", "") when c is nil so callers do not need to guard the call. Mirrors the precedence applied at runtime when sending the client_id on token refresh: cached CIMD URL > cached DCR client_id > statically configured client_id. Lives next to resolveClientCredentials so the precedence has a single home — adding a fourth cached field updates both call sites in one place.
func (*Config) UnmarshalJSON ¶
UnmarshalJSON implements custom JSON unmarshaling for backward compatibility This handles both the old PascalCase format and the new snake_case format
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler handles authentication for remote MCP servers. Supports OAuth/OIDC-based authentication with automatic discovery.
func NewHandler ¶
NewHandler creates a new remote authentication handler
func (*Handler) Authenticate ¶
Authenticate is the main entry point for remote MCP server authentication
func (*Handler) SetClientCredentialsPersister ¶ added in v0.9.0
func (h *Handler) SetClientCredentialsPersister(persister ClientCredentialsPersister)
SetClientCredentialsPersister sets a callback function that will be called when DCR client credentials are obtained and need to be persisted.
func (*Handler) SetHTTPClient ¶ added in v0.41.0
func (h *Handler) SetHTTPClient(client networking.HTTPClient)
SetHTTPClient sets the HTTP client used for RFC 7592 registration management requests.
func (*Handler) SetSecretProvider ¶ added in v0.8.1
SetSecretProvider sets the secret provider used to store and retrieve cached tokens.
func (*Handler) SetTokenPersister ¶ added in v0.8.1
func (h *Handler) SetTokenPersister(persister TokenPersister)
SetTokenPersister sets a callback function that will be called whenever OAuth tokens are refreshed. This enables token persistence across restarts.
type PersistingTokenSource ¶ added in v0.8.1
type PersistingTokenSource struct {
// contains filtered or unexported fields
}
PersistingTokenSource wraps an oauth2.TokenSource and persists tokens whenever they are refreshed. This enables session restoration across workload restarts without requiring a new browser-based OAuth flow.
func NewPersistingTokenSource ¶ added in v0.8.1
func NewPersistingTokenSource(source oauth2.TokenSource, persister TokenPersister) *PersistingTokenSource
NewPersistingTokenSource creates a new PersistingTokenSource that wraps the given token source and calls the persister function whenever tokens are refreshed.
type TokenPersister ¶ added in v0.8.1
TokenPersister is a callback function that persists a cached OAuth session. It is called whenever tokens are refreshed. Only the cached session is persisted since the access token can be regenerated from it.
The value passed is opaque and must be stored and returned unchanged: Handler may pass either a bare refresh token (legacy) or a versioned envelope binding the token to the authorization server that issued it (see cachedRefreshTokenEnvelope). Persisters must not assume the value is a directly-usable refresh token.