mcpauth

package
v0.1.0-beta.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package mcpauth implements downstream OAuth 2.1 brokering for external MCP servers: authorization-server discovery (RFC 9728 / RFC 8414), dynamic client registration (RFC 7591), the authorization-code + PKCE flow, and encrypted token persistence with refresh rotation.

The name avoids "auth" to keep it distinct from the gateway's inbound API authentication (internal/api/auth.go).

Index

Constants

View Source
const CallbackPath = "/oauth/callback"

CallbackPath is the route the broker's redirect URI points at. It is mounted on the gateway's existing listener, outside the inbound API auth middleware: the callback authenticates via the single-use state parameter, and the browser performing the redirect holds no gateway bearer token.

View Source
const DefaultAuthTimeout = 5 * time.Minute

DefaultAuthTimeout bounds how long a pending authorization waits for the browser callback before it expires with no partial state.

Variables

View Source
var ErrDCRUnsupported = errors.New(
	"authorization server does not support dynamic client registration; " +
		"set auth.client_id (and auth.client_secret if issued) in stack.yaml")

ErrDCRUnsupported reports an authorization server that refuses dynamic client registration. The message names the fix because it is shown to the user verbatim.

Functions

This section is empty.

Types

type Broker

type Broker struct {
	// contains filtered or unexported fields
}

Broker owns downstream OAuth state: discovery, client identity, the authorization-code + PKCE flow, token persistence, and refresh rotation.

func NewBroker

func NewBroker(store *TokenStore, redirectURL string, logger *slog.Logger) *Broker

NewBroker constructs a broker persisting into store, with the given daemon callback URL.

func (*Broker) BeginAuthorization

func (b *Broker) BeginAuthorization(ctx context.Context, server string, timeout time.Duration) (authorizeURL, authState string, err error)

BeginAuthorization starts the authorization-code flow for a configured server: discovery, client identity resolution (static config, cached registration, then DCR), PKCE, and the composed authorization URL. It returns the URL for the caller to open (the broker never opens a browser) and the single-use state that keys the pending flow.

func (*Broker) CallbackHandler

func (b *Broker) CallbackHandler() http.Handler

CallbackHandler returns the HTTP handler for the authorization redirect. It completes the pending flow and renders a small self-closing page; all real error detail stays on the CLI/API waiter side.

func (*Broker) CompleteAuthorization

func (b *Broker) CompleteAuthorization(ctx context.Context, stateToken, code, iss string) error

CompleteAuthorization redeems an authorization code delivered to the callback (or pasted manually). state is single-use; iss, when the AS returned one, must match the recorded issuer (RFC 9207).

func (*Broker) CompleteManual

func (b *Broker) CompleteManual(ctx context.Context, redirectURL string) error

CompleteManual accepts a full pasted redirect URL (the --manual path for SSH sessions where the loopback callback cannot reach the daemon).

func (*Broker) Configure

func (b *Broker) Configure(server, serverURL string, auth *mcp.ServerAuthConfig) error

Configure registers (or updates) the OAuth config for a server and reflects its current state into the sink: authorized when a usable grant already exists for the resource, needs-auth otherwise.

func (*Broker) Deconfigure

func (b *Broker) Deconfigure(server string)

Deconfigure removes a server from the broker without touching stored grants (other stacks may share them; RemoveServerGrant handles cleanup).

func (*Broker) FailAuthorization

func (b *Broker) FailAuthorization(stateToken string, cause error)

FailAuthorization resolves a pending flow with an error (an AS denial such as access_denied), waking any waiter immediately instead of letting it run out the flow timeout. Unknown or already-resolved states are a no-op.

func (*Broker) HeaderSource

func (b *Broker) HeaderSource(server string) mcp.HeaderSource

HeaderSource returns the live token source for a configured server. The same instance is reused so its cached token survives across requests.

func (*Broker) HeaderSourceForResource

func (b *Broker) HeaderSourceForResource(serverURL string) mcp.HeaderSource

HeaderSourceForResource returns a header source bound to a raw resource URL rather than a configured server name. The probe uses it so a pre-apply token acquired in the wizard carries over to the applied server (both key by canonical resource URL).

func (*Broker) Logout

func (b *Broker) Logout(ctx context.Context, server string) error

Logout revokes (best effort, RFC 7009) and deletes the grant backing a configured server.

func (*Broker) RemoveServerGrant

func (b *Broker) RemoveServerGrant(ctx context.Context, server string) error

RemoveServerGrant is the stack-removal cleanup path: it revokes and deletes the grant only when no other configured server shares the resource.

func (*Broker) Reset

func (b *Broker) Reset(ctx context.Context, server string) error

Reset deletes the grant and the issuer's cached client registration for a server: the first-class version of mcp-remote's rm -rf escape hatch.

func (*Broker) ServerStatus

func (b *Broker) ServerStatus(server string) (ServerAuthInfo, error)

ServerStatus returns authorization info for one configured server.

func (*Broker) SetOnAuthorized

func (b *Broker) SetOnAuthorized(fn func(server string))

SetOnAuthorized installs a callback fired after a successful authorization; the controller uses it to re-register the server.

func (*Broker) SetRedactor

func (b *Broker) SetRedactor(fn func(values []string))

SetRedactor installs the log-redaction hook. Every access and refresh token is registered the moment it enters memory, before any code path can log a request or response containing it.

func (*Broker) SetStateSink

func (b *Broker) SetStateSink(sink StateSink)

SetStateSink installs the gateway hook that receives state transitions.

func (*Broker) Status

func (b *Broker) Status() []ServerAuthInfo

Status returns per-server authorization info for every configured server.

func (*Broker) Wait

func (b *Broker) Wait(ctx context.Context, stateToken string) error

Wait blocks until the flow keyed by state completes, fails, or expires.

type ClientRegistration

type ClientRegistration struct {
	Issuer       string    `json:"issuer"`
	ClientID     string    `json:"clientId"`
	ClientSecret string    `json:"clientSecret,omitempty"`
	RedirectURI  string    `json:"redirectUri"`
	CreatedAt    time.Time `json:"createdAt"`
}

ClientRegistration is a dynamically registered OAuth client, keyed by issuer (SEP-2352: credentials are bound to the issuing AS and never reused with a different one).

type Grant

type Grant struct {
	Resource  string        `json:"resource"`         // canonical resource URL
	Issuer    string        `json:"issuer"`           // authorization server issuer
	Scopes    []string      `json:"scopes,omitempty"` // granted scopes
	Token     *oauth2.Token `json:"token"`            // access + refresh token
	UpdatedAt time.Time     `json:"updatedAt"`

	// Endpoints captured at authorization time so refresh and revocation
	// work across daemon restarts without re-running discovery.
	TokenEndpoint      string `json:"tokenEndpoint"`
	RevocationEndpoint string `json:"revocationEndpoint,omitempty"`
}

Grant is one authorization against a downstream server, keyed by the canonical resource URL. Two stacks pointing at the same endpoint share a grant, and renaming a server in stack.yaml does not force a re-login.

type ServerAuthInfo

type ServerAuthInfo struct {
	Server   string     `json:"server"`
	Resource string     `json:"resource"`
	Status   string     `json:"status"` // mcp.AuthStatusAuthorized | mcp.AuthStatusNeedsAuth
	Issuer   string     `json:"issuer,omitempty"`
	Scopes   []string   `json:"scopes,omitempty"`
	Expiry   *time.Time `json:"expiry,omitempty"`
}

ServerAuthInfo is the per-server view returned to the CLI and API.

type StateSink

type StateSink interface {
	SetServerAuthState(name string, st mcp.ServerAuthState)
}

StateSink receives authorization state transitions; *mcp.Gateway satisfies it. A nil sink is valid (probe-only broker use).

type TokenStore

type TokenStore struct {
	// contains filtered or unexported fields
}

TokenStore persists OAuth grants and client registrations encrypted at rest under the gridctl state directory. All operations take a cross- process flock and re-read the file, so a CLI-driven authorization is observed by the running daemon on its next access.

func NewTokenStore

func NewTokenStore(dir string) (*TokenStore, error)

NewTokenStore opens (creating if needed) the token store rooted at dir. When dir is empty, <state base dir>/oauth is used.

func (*TokenStore) DeleteGrant

func (s *TokenStore) DeleteGrant(resource string) error

DeleteGrant removes the grant for a resource. Missing grants are a no-op.

func (*TokenStore) DeleteRegistration

func (s *TokenStore) DeleteRegistration(issuer string) error

DeleteRegistration removes the registered client for an issuer.

func (*TokenStore) Grant

func (s *TokenStore) Grant(resource string) (Grant, bool, error)

Grant returns the stored grant for a canonical resource URL.

func (*TokenStore) Grants

func (s *TokenStore) Grants() (map[string]Grant, error)

GrantsByIssuerResource reports how many stored grants share the given issuer and resource; used for the cross-stack refcount before revoking on server removal.

func (*TokenStore) PutGrant

func (s *TokenStore) PutGrant(g Grant) error

PutGrant stores (or replaces) the grant for its resource. Called on initial authorization and again on every refresh-token rotation.

func (*TokenStore) PutRegistration

func (s *TokenStore) PutRegistration(r ClientRegistration) error

PutRegistration stores a registered client keyed by issuer.

func (*TokenStore) Registration

func (s *TokenStore) Registration(issuer string) (ClientRegistration, bool, error)

Registration returns the stored client registration for an issuer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL