Documentation
¶
Overview ¶
Package mcp_headers implements schemas.MCPHeadersProvider against the configstore. It is the storage backend for MCPAuthTypePerUserHeaders MCP clients — the parallel of framework/oauth2 for the OAuth-flavored per-user auth type.
The provider is intentionally storage-only: it does not run upstream verification (that's clientmanager.VerifyHeadersConnection) and does not build inline-401 errors (that's the credstore resolver). It just maps between the table type and the in-memory schema view.
Index ¶
- Constants
- type CredentialSweepWorker
- type Provider
- func (p *Provider) DeleteCredential(ctx context.Context, id string) error
- func (p *Provider) EvictCredential(mode schemas.MCPAuthMode, identity, mcpClientID string)
- func (p *Provider) EvictCredentialByID(id string)
- func (p *Provider) EvictCredentialsByMCPClient(mcpClientID string)
- func (p *Provider) EvictCredentialsByUser(userID string)
- func (p *Provider) EvictCredentialsByVirtualKey(virtualKeyID string)
- func (p *Provider) FlushCredentialCache()
- func (p *Provider) GetCredentialByMode(ctx context.Context, mode schemas.MCPAuthMode, identity, mcpClientID string) (*schemas.MCPHeadersUserCredential, error)
- func (p *Provider) InitiateUserSubmissionFlow(ctx context.Context, mode schemas.MCPAuthMode, ...) (*schemas.MCPHeadersFlowInitiation, error)
- func (p *Provider) SetTempTokenService(svc *temptoken.Service)
- func (p *Provider) UpsertCredential(ctx context.Context, cred *schemas.MCPHeadersUserCredential) error
Constants ¶
const SubmissionFlowTTL = 15 * time.Minute
SubmissionFlowTTL caps how long a pending headers submission flow row (and the temp token bound to it) remains valid. Mirrors the OAuth flow expiry so the two per-user-auth surfaces feel uniform to the user.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CredentialSweepWorker ¶
type CredentialSweepWorker struct {
// contains filtered or unexported fields
}
CredentialSweepWorker periodically purges stale per-user header credentials AND expired pending submission-flow rows. Two independent sweeps run on the same goroutine:
- Orphan credential sweep: rows that have been in 'orphaned' state (VK lost access) longer than OrphanRetention are hard-deleted.
- Expired flow sweep: pending flow rows whose ExpiresAt has passed (caller never completed the submission, link aged out) are hard-deleted. Tighter cadence than the orphan sweep because flow rows are short-lived (15 min TTL).
Mirrors oauth2.PerUserOAuthSweepWorker, which combines the same two concerns on the OAuth side.
Defaults: 24h orphan cadence, 15 min flow-expiry cadence. Non-positive orphanRetention disables the orphan sweep entirely; the expired-flow sweep always runs because flow rows have no semantic value past their expiry.
func NewCredentialSweepWorker ¶
func NewCredentialSweepWorker(provider *Provider, orphanRetention time.Duration, logger schemas.Logger) *CredentialSweepWorker
NewCredentialSweepWorker creates a sweep worker with sensible defaults. orphanRetention <= 0 disables the orphan sweep (the worker still starts but the tick is a no-op — keeps wiring uniform).
func (*CredentialSweepWorker) SetOrphanSweepInterval ¶
func (w *CredentialSweepWorker) SetOrphanSweepInterval(d time.Duration)
SetOrphanSweepInterval updates the orphan-sweep cadence (for testing). Non-positive durations are ignored — run() feeds the field straight into time.NewTicker, which panics on d <= 0.
func (*CredentialSweepWorker) Start ¶
func (w *CredentialSweepWorker) Start(ctx context.Context)
Start begins the sweep worker in a background goroutine.
func (*CredentialSweepWorker) Stop ¶
func (w *CredentialSweepWorker) Stop()
Stop gracefully stops the sweep worker. sync.Once guards against double-close panics from redundant shutdown paths.
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider implements schemas.MCPHeadersProvider.
func NewProvider ¶
func NewProvider(configStore configstore.ConfigStore, logger schemas.Logger) *Provider
NewProvider constructs a configstore-backed MCPHeadersProvider. Mirrors oauth2.NewOAuth2Provider so the wiring in transports/bifrost-http stays symmetric between the two per-user auth surfaces.
func (*Provider) DeleteCredential ¶
DeleteCredential removes a credential by primary key.
func (*Provider) EvictCredential ¶ added in v1.5.9
func (p *Provider) EvictCredential(mode schemas.MCPAuthMode, identity, mcpClientID string)
EvictCredential drops the cached credential for one (mode, identity, mcp client) binding. Side-effect only and safe to call when the cache is absent; the next lookup for the binding reads the database.
func (*Provider) EvictCredentialByID ¶ added in v1.5.9
EvictCredentialByID drops the cached credential backed by the given row ID, if any binding currently holds it. Side-effect only and safe to call when the cache is absent or the ID is not cached.
func (*Provider) EvictCredentialsByMCPClient ¶ added in v1.5.9
EvictCredentialsByMCPClient drops every cached credential bound to the given MCP client, across all auth modes and identities. Used after client-level mutations that invalidate its credential rows as a set, such as a needs_update schema flip, access reconciliation, or client deletion. Side-effect only and safe to call when the cache is absent.
func (*Provider) EvictCredentialsByUser ¶ added in v1.5.9
EvictCredentialsByUser drops every cached user-mode credential bound to the given user, across all MCP clients. Used after user-level mutations that orphan or delete the user's credential rows as a set. Side-effect only and safe to call when the cache is absent.
func (*Provider) EvictCredentialsByVirtualKey ¶ added in v1.5.9
EvictCredentialsByVirtualKey drops every cached vk-mode credential bound to the given virtual key, across all MCP clients. Used after virtual key mutations that orphan or delete its credential rows as a set. Side-effect only and safe to call when the cache is absent.
func (*Provider) FlushCredentialCache ¶ added in v1.5.9
func (p *Provider) FlushCredentialCache()
FlushCredentialCache drops every cached per-user header credential. The coarse fallback for mutations whose blast radius cannot be scoped to one client or virtual key. Side-effect only.
func (*Provider) GetCredentialByMode ¶
func (p *Provider) GetCredentialByMode(ctx context.Context, mode schemas.MCPAuthMode, identity, mcpClientID string) (*schemas.MCPHeadersUserCredential, error)
GetCredentialByMode looks up the active credential row for the given identity dimension. Returns ErrHeadersCredentialNotFound when the row is absent so callers can switch on the sentinel. mode can also be MCPAuthModeAdmin: the retained bootstrap credential has no per-caller identity, so identity is allowed empty in that case alone.
Reads are served from an in-memory cache when possible. Both 'active' and 'needs_update' rows are cached with their status carried through, since the store lookup deliberately returns both and callers decide usability themselves. Header credentials have no expiry, so a cached entry is served until an eviction removes it. Failed lookups (including not-found) are never cached, so a caller completing a submission flow becomes visible on the very next call. Every hit returns a fresh deep copy so a caller mutating the result can never corrupt the cached value.
func (*Provider) InitiateUserSubmissionFlow ¶
func (p *Provider) InitiateUserSubmissionFlow(ctx context.Context, mode schemas.MCPAuthMode, identity, mcpClientID, baseURL string) (*schemas.MCPHeadersFlowInitiation, error)
InitiateUserSubmissionFlow creates a pending mcp_per_user_header_flows row keyed by (mode, identity, mcp_client_id), mints a mcp_headers_auth temp-token bound to the new row's ID, and returns the auth-page URL with the token embedded as a `#t=<token>` fragment. Mirrors oauth2.OAuth2Provider.InitiateUserOAuthFlow.
The temp-token mint is best-effort: if it fails, the URL is returned without a fragment and remains usable for callers already authenticated to the dashboard. The behavior is the same as the OAuth equivalent so the two surfaces feel uniform.
func (*Provider) SetTempTokenService ¶
SetTempTokenService installs the temp-token service used by InitiateUserSubmissionFlow to mint the mcp_headers_auth token embedded in the auth-page URL fragment. Called by server startup once both services have been constructed (the provider is built first by lib/config.go, the service later by the HTTP transport).
func (*Provider) UpsertCredential ¶
func (p *Provider) UpsertCredential(ctx context.Context, cred *schemas.MCPHeadersUserCredential) error
UpsertCredential persists the caller-supplied credential. The caller is expected to have run clientmanager.VerifyHeadersConnection before invoking this — the provider trusts the values and only handles serialization + storage.