auth

package
v1.0.8 Latest Latest
Warning

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

Go to latest
Published: May 14, 2026 License: MIT Imports: 35 Imported by: 0

Documentation

Index

Constants

View Source
const RequestedModelMetadataKey = "requested_model"

RequestedModelMetadataKey stores the client-requested model name in Options.Metadata. It is used to preserve the original model string across prefix rewriting / alias resolution.

Variables

View Source
var ErrFullAuthNotFound = errors.New("full auth not found")

Functions

func ApplyCustomHeadersFromMetadata

func ApplyCustomHeadersFromMetadata(auth *Auth)

ApplyCustomHeadersFromMetadata updates apply custom headers from metadata.

func ExtractCustomHeadersFromMetadata

func ExtractCustomHeadersFromMetadata(metadata map[string]any) map[string]string

ExtractCustomHeadersFromMetadata extracts a custom headers from metadata.

func ExtractSessionID

func ExtractSessionID(headers http.Header, payload []byte, metadata map[string]any) string

ExtractSessionID extracts session identifier from multiple sources. Priority order:

  1. metadata.user_id (Claude Code format with _session_{uuid}) - highest priority for Claude Code clients
  2. X-Session-ID header
  3. Session_id header (Codex)
  4. X-Amp-Thread-Id header (Amp CLI thread ID)
  5. X-Client-Request-Id header (PI)
  6. metadata.user_id (non-Claude Code format)
  7. conversation_id field in request body
  8. Stable hash from first few messages content (fallback)

func OAuthModelAliasChannel

func OAuthModelAliasChannel(provider, authKind string) string

OAuthModelAliasChannel returns the OAuth model alias channel name for a given provider and auth kind. Returns empty string if the provider/authKind combination doesn't support OAuth model alias (e.g., API key authentication).

Supported channels: gemini-cli, vertex, aistudio, antigravity, claude, codex, kimi.

func ProviderRefreshLead

func ProviderRefreshLead(provider string, runtime any) *time.Duration

ProviderRefreshLead handles a provider refresh lead.

func RegisterRefreshLeadProvider

func RegisterRefreshLeadProvider(provider string, factory func() *time.Duration)

RegisterRefreshLeadProvider handles a register refresh lead provider.

func RegisterTokenStore

func RegisterTokenStore(store Store)

RegisterTokenStore sets the global token store used by the authentication helpers.

func WithRequestInfo

func WithRequestInfo(ctx context.Context, info *RequestInfo) context.Context

WithRequestInfo returns a new context with the given RequestInfo attached.

func WithSkipPersist

func WithSkipPersist(ctx context.Context) context.Context

WithSkipPersist returns a derived context that disables persistence for Manager Update/Register calls. It is intended for code paths that are reacting to file watcher events, where the file on disk is already the source of truth and persisting again would create a write-back loop.

Types

type Auth

type Auth struct {
	// ID uniquely identifies the auth record across restarts.
	ID string `json:"id"`
	// Index is a stable runtime identifier derived from auth metadata (not persisted).
	Index string `json:"-"`
	// Provider is the upstream provider key (e.g. "gemini", "claude").
	Provider string `json:"provider"`
	// Prefix optionally namespaces models for routing (e.g., "teamA/gemini-3-pro-preview").
	Prefix string `json:"prefix,omitempty"`
	// FileName stores the relative or absolute path of the backing auth file.
	FileName string `json:"-"`
	// Storage holds the token persistence implementation used during login flows.
	Storage baseauth.TokenStorage `json:"-"`
	// Label is an optional human readable label for logging.
	Label string `json:"label,omitempty"`
	// Status is the lifecycle status managed by the AuthManager.
	Status Status `json:"status"`
	// StatusMessage holds a short description for the current status.
	StatusMessage string `json:"status_message,omitempty"`
	// Disabled indicates the auth is intentionally disabled by operator.
	Disabled bool `json:"disabled"`
	// Unavailable flags transient provider unavailability (e.g. quota exceeded).
	Unavailable bool `json:"unavailable"`
	// ProxyURL overrides the global proxy setting for this auth if provided.
	ProxyURL string `json:"proxy_url,omitempty"`
	// Attributes stores provider specific metadata needed by executors (immutable configuration).
	Attributes map[string]string `json:"attributes,omitempty"`
	// Metadata stores runtime mutable provider state (e.g. tokens, cookies).
	Metadata map[string]any `json:"metadata,omitempty"`
	// Quota captures recent quota information for load balancers.
	Quota QuotaState `json:"quota"`
	// LastError stores the last failure encountered while executing or refreshing.
	LastError *Error `json:"last_error,omitempty"`
	// CreatedAt is the creation timestamp in UTC.
	CreatedAt time.Time `json:"created_at"`
	// UpdatedAt is the last modification timestamp in UTC.
	UpdatedAt time.Time `json:"updated_at"`
	// LastRefreshedAt records the last successful refresh time in UTC.
	LastRefreshedAt time.Time `json:"last_refreshed_at"`
	// NextRefreshAfter is the earliest time a refresh should retrigger.
	NextRefreshAfter time.Time `json:"next_refresh_after"`
	// NextRetryAfter is the earliest time a retry should retrigger.
	NextRetryAfter time.Time `json:"next_retry_after"`
	// ModelStates tracks per-model runtime availability data.
	ModelStates map[string]*ModelState `json:"model_states,omitempty"`

	// Runtime carries non-serialisable data used during execution (in-memory only).
	Runtime any `json:"-"`

	Success int64 `json:"-"`
	Failed  int64 `json:"-"`
	// contains filtered or unexported fields
}

Auth encapsulates the runtime state and metadata associated with a single credential.

func (*Auth) AccountInfo

func (a *Auth) AccountInfo() (string, string)

AccountInfo handles an account info.

func (*Auth) Clone

func (a *Auth) Clone() *Auth

Clone shallow copies the Auth structure, duplicating maps to avoid accidental mutation.

func (*Auth) DisableCoolingOverride

func (a *Auth) DisableCoolingOverride() (bool, bool)

DisableCoolingOverride returns the auth-scoped disable_cooling override when present. This override is true-only: false is treated as unset so the global flag can still apply. The value is read from metadata key "disable_cooling" (or legacy "disable-cooling").

func (*Auth) EnsureIndex

func (a *Auth) EnsureIndex() string

EnsureIndex returns a stable index derived from the auth file name or credential identity.

func (*Auth) ExpirationTime

func (a *Auth) ExpirationTime() (time.Time, bool)

ExpirationTime attempts to extract the credential expiration timestamp from metadata. It inspects common keys such as "expired", "expire", "expires_at", and also nested "token" objects to remain compatible with legacy auth file formats.

func (*Auth) ProxyInfo

func (a *Auth) ProxyInfo() string

ProxyInfo handles a proxy info.

func (*Auth) RecentRequestsSnapshot

func (a *Auth) RecentRequestsSnapshot(now time.Time) []RecentRequestBucket

RecentRequestsSnapshot handles a recent requests snapshot.

func (*Auth) RequestRetryOverride

func (a *Auth) RequestRetryOverride() (int, bool)

RequestRetryOverride returns the auth-file scoped request_retry override when present. The value is read from metadata key "request_retry" (or legacy "request-retry").

func (*Auth) ToolPrefixDisabled

func (a *Auth) ToolPrefixDisabled() bool

ToolPrefixDisabled returns whether the proxy_ tool name prefix should be skipped for this auth. When true, tool names are sent to Anthropic unchanged. The value is read from metadata key "tool_prefix_disabled" (or "tool-prefix-disabled").

type DispatchDecision

type DispatchDecision struct {
	Auth          *Auth
	Provider      string
	UpstreamModel string
	PooledModels  bool
}

DispatchDecision captures the scheduler selection for an incoming request.

type Error

type Error struct {
	// Code is a short machine readable identifier.
	Code string `json:"code,omitempty"`
	// Message is a human readable description of the failure.
	Message string `json:"message"`
	// Retryable indicates whether a retry might fix the issue automatically.
	Retryable bool `json:"retryable"`
	// HTTPStatus optionally records an HTTP-like status code for the error.
	HTTPStatus int `json:"http_status,omitempty"`
}

Error describes an authentication related failure in a provider agnostic format.

func (*Error) Error

func (e *Error) Error() string

Error returns the error message.

func (*Error) StatusCode

func (e *Error) StatusCode() int

StatusCode returns the HTTP status code.

type FileTokenStore

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

FileTokenStore persists token records and auth metadata using the filesystem as backing storage.

func NewFileTokenStore

func NewFileTokenStore() *FileTokenStore

NewFileTokenStore creates a token store that saves credentials to disk through the TokenStorage implementation embedded in the token record.

func (*FileTokenStore) Delete

func (s *FileTokenStore) Delete(ctx context.Context, id string) error

Delete removes the auth file.

func (*FileTokenStore) List

func (s *FileTokenStore) List(ctx context.Context) ([]*Auth, error)

List enumerates all auth JSON files under the configured directory.

func (*FileTokenStore) Save

func (s *FileTokenStore) Save(ctx context.Context, auth *Auth) (string, error)

Save persists token storage and metadata to the resolved auth file path.

func (*FileTokenStore) SetBaseDir

func (s *FileTokenStore) SetBaseDir(dir string)

SetBaseDir updates the default directory used for auth JSON persistence when no explicit path is provided.

type FillFirstSelector

type FillFirstSelector struct{}

FillFirstSelector selects the first available credential (deterministic ordering). This "burns" one account before moving to the next, which can help stagger rolling-window subscription caps (e.g. chat message limits).

func (*FillFirstSelector) Pick

func (s *FillFirstSelector) Pick(ctx context.Context, provider, model string, opts Options, auths []*Auth) (*Auth, error)

Pick selects the first available auth for the provider in a deterministic manner.

type FullAuthResolver

type FullAuthResolver interface {
	GetFullAuth(ctx context.Context, uuid string) (*Auth, error)
}

type Manager

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

Manager orchestrates auth lifecycle, selection, and persistence for CLIProxyAPIHome.

This is intentionally narrower than CPA's full execution manager: it only supports registering/updating auths, scheduling selection (Dispatch), and background refresh.

func NewManager

func NewManager(store Store, selector Selector, _ any) *Manager

NewManager creates a new manager.

func (*Manager) Delete

func (m *Manager) Delete(ctx context.Context, id string) error

Delete handles delete.

func (*Manager) Dispatch

func (m *Manager) Dispatch(ctx context.Context, providers []string, requestedModel string, opts Options) (*DispatchDecision, error)

Dispatch processes dispatch.

func (*Manager) GetByID

func (m *Manager) GetByID(id string) (*Auth, bool)

GetByID returns a by id.

func (*Manager) GetByIndex

func (m *Manager) GetByIndex(index string) (*Auth, bool)

GetByIndex returns a by index.

func (*Manager) List

func (m *Manager) List() []*Auth

List returns the available entries.

func (*Manager) MarkResult

func (m *Manager) MarkResult(ctx context.Context, result Result)

MarkResult records a downstream execution result and updates auth cooldown state.

func (*Manager) ReconcileRegistryModelStates

func (m *Manager) ReconcileRegistryModelStates(_ context.Context, _ string)

ReconcileRegistryModelStates reconciles a registry model states.

func (*Manager) RefreshAuthCredential

func (m *Manager) RefreshAuthCredential(ctx context.Context, target *Auth) (*Auth, error)

RefreshAuthCredential refreshes a full auth value without updating memory or persistence.

func (*Manager) RefreshNow

func (m *Manager) RefreshNow(ctx context.Context, authIndex string) (*Auth, error)

RefreshNow forces a best-effort credential refresh for the given auth. It updates the in-memory record and persists it when enabled.

func (*Manager) RefreshSchedulerEntry

func (m *Manager) RefreshSchedulerEntry(authID string)

RefreshSchedulerEntry refreshes refresh scheduler entry.

func (*Manager) Register

func (m *Manager) Register(ctx context.Context, auth *Auth) (*Auth, error)

Register wires package handlers into the provided registry.

func (*Manager) SetConfig

func (m *Manager) SetConfig(cfg *internalconfig.Config)

SetConfig sets a config.

func (*Manager) SetFullAuthResolver

func (m *Manager) SetFullAuthResolver(resolver FullAuthResolver)

SetFullAuthResolver sets a full auth resolver.

func (*Manager) SetOAuthModelAlias

func (m *Manager) SetOAuthModelAlias(aliases map[string][]internalconfig.OAuthModelAlias)

SetOAuthModelAlias updates the OAuth model name alias table used during execution. The alias is applied per-auth channel to resolve the upstream model name while keeping the client-visible model name unchanged for translation/response formatting.

func (*Manager) SetRoundTripperProvider

func (m *Manager) SetRoundTripperProvider(p RoundTripperProvider)

SetRoundTripperProvider sets a round tripper provider.

func (*Manager) SetSelector

func (m *Manager) SetSelector(selector Selector)

SetSelector sets a selector.

func (*Manager) SetStore

func (m *Manager) SetStore(store Store)

SetStore sets a store.

func (*Manager) Shutdown

func (m *Manager) Shutdown()

Shutdown manages shutdown.

func (*Manager) StartAutoRefresh

func (m *Manager) StartAutoRefresh(parent context.Context, interval time.Duration)

StartAutoRefresh starts an auto refresh.

func (*Manager) StopAutoRefresh

func (m *Manager) StopAutoRefresh()

StopAutoRefresh stops an auto refresh.

func (*Manager) Update

func (m *Manager) Update(ctx context.Context, auth *Auth) (*Auth, error)

Update updates the value.

type ModelState

type ModelState struct {
	// Status reflects the lifecycle status for this model.
	Status Status `json:"status"`
	// StatusMessage provides an optional short description of the status.
	StatusMessage string `json:"status_message,omitempty"`
	// Unavailable mirrors whether the model is temporarily blocked for retries.
	Unavailable bool `json:"unavailable"`
	// NextRetryAfter defines the per-model retry time.
	NextRetryAfter time.Time `json:"next_retry_after"`
	// LastError records the latest error observed for this model.
	LastError *Error `json:"last_error,omitempty"`
	// Quota retains quota information if this model hit rate limits.
	Quota QuotaState `json:"quota"`
	// UpdatedAt tracks the last update timestamp for this model state.
	UpdatedAt time.Time `json:"updated_at"`
}

ModelState captures the execution state for a specific model under an auth entry.

func (*ModelState) Clone

func (m *ModelState) Clone() *ModelState

Clone duplicates a model state including nested error details.

type Options

type Options struct {
	Headers         http.Header
	Query           url.Values
	OriginalRequest []byte
	Metadata        map[string]any
}

Options carries optional request hints used during dispatch selection.

This is a deliberately small subset of CPA's execution options: CLIProxyAPIHome only needs headers / query / raw request bytes for selector decisions, and a generic metadata bag.

type PostAuthHook

type PostAuthHook func(context.Context, *Auth) error

PostAuthHook defines a function that is called after an Auth record is created but before it is persisted to storage. This allows for modification of the Auth record (e.g., injecting metadata) based on external context.

type QuotaState

type QuotaState struct {
	// Exceeded indicates the credential recently hit a quota error.
	Exceeded bool `json:"exceeded"`
	// Reason provides an optional provider specific human readable description.
	Reason string `json:"reason,omitempty"`
	// NextRecoverAt is when the credential may become available again.
	NextRecoverAt time.Time `json:"next_recover_at"`
	// BackoffLevel stores the progressive cooldown exponent used for rate limits.
	BackoffLevel int `json:"backoff_level,omitempty"`
}

QuotaState contains limiter tracking data for a credential.

type RecentRequestBucket

type RecentRequestBucket struct {
	Time    string `json:"time"`
	Success int64  `json:"success"`
	Failed  int64  `json:"failed"`
}

type RefreshEvaluator

type RefreshEvaluator interface {
	ShouldRefresh(now time.Time, auth *Auth) bool
}

RefreshEvaluator allows runtime state to override refresh decisions.

type RequestInfo

type RequestInfo struct {
	Query   url.Values
	Headers http.Header
}

RequestInfo holds information extracted from the HTTP request. It is injected into the context passed to PostAuthHook.

func GetRequestInfo

func GetRequestInfo(ctx context.Context) *RequestInfo

GetRequestInfo retrieves the RequestInfo from the context, if present.

type Result

type Result struct {
	AuthID    string
	AuthIndex string
	Provider  string
	Model     string
	Success   bool
	Error     *Error
}

Result captures an upstream execution result reported by a downstream CPA node.

func NewUsageResult

func NewUsageResult(authIndex, provider, model string, statusCode int, body string) Result

NewUsageResult creates a new usage result.

type RoundRobinSelector

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

RoundRobinSelector provides a simple provider scoped round-robin selection strategy.

func (*RoundRobinSelector) Pick

func (s *RoundRobinSelector) Pick(ctx context.Context, provider, model string, opts Options, auths []*Auth) (*Auth, error)

Pick selects the next available auth for the provider in a round-robin manner. For gemini-cli virtual auths (identified by the gemini_virtual_parent attribute), a two-level round-robin is used: first cycling across credential groups (parent accounts), then cycling within each group's project auths.

type RoundTripperProvider

type RoundTripperProvider interface {
	RoundTripperFor(auth *Auth) http.RoundTripper
}

RoundTripperProvider defines a minimal provider of per-auth HTTP transports.

type Selector

type Selector interface {
	Pick(ctx context.Context, provider, model string, opts Options, auths []*Auth) (*Auth, error)
}

Selector chooses an auth candidate for dispatch.

type SessionAffinityConfig

type SessionAffinityConfig struct {
	Fallback Selector
	TTL      time.Duration
}

SessionAffinityConfig configures the session affinity selector.

type SessionAffinitySelector

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

SessionAffinitySelector wraps another selector with session-sticky behavior. It extracts session ID from multiple sources and maintains session-to-auth mappings with automatic failover when the bound auth becomes unavailable.

func NewSessionAffinitySelector

func NewSessionAffinitySelector(fallback Selector) *SessionAffinitySelector

NewSessionAffinitySelector creates a new session-aware selector.

func NewSessionAffinitySelectorWithConfig

func NewSessionAffinitySelectorWithConfig(cfg SessionAffinityConfig) *SessionAffinitySelector

NewSessionAffinitySelectorWithConfig creates a selector with custom configuration.

func (*SessionAffinitySelector) InvalidateAuth

func (s *SessionAffinitySelector) InvalidateAuth(authID string)

InvalidateAuth removes all session bindings for a specific auth. Called when an auth becomes rate-limited or unavailable.

func (*SessionAffinitySelector) Pick

func (s *SessionAffinitySelector) Pick(ctx context.Context, provider, model string, opts Options, auths []*Auth) (*Auth, error)

Pick selects an auth with session affinity when possible. Priority for session ID extraction:

  1. metadata.user_id (Claude Code format with _session_{uuid}) - highest priority
  2. X-Session-ID header
  3. Session_id header (Codex)
  4. X-Amp-Thread-Id header (Amp CLI thread ID)
  5. X-Client-Request-Id header (PI)
  6. metadata.user_id (non-Claude Code format)
  7. conversation_id field in request body
  8. Stable hash from first few messages content (fallback)

Note: The cache key includes provider, session ID, and model to handle cases where a session uses multiple models (e.g., gemini-2.5-pro and gemini-3-flash-preview) that may be supported by different auth credentials, and to avoid cross-provider conflicts.

func (*SessionAffinitySelector) Stop

func (s *SessionAffinitySelector) Stop()

Stop releases resources held by the selector.

type SessionCache

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

SessionCache provides TTL-based session to auth mapping with automatic cleanup.

func NewSessionCache

func NewSessionCache(ttl time.Duration) *SessionCache

NewSessionCache creates a cache with the specified TTL. A background goroutine periodically cleans expired entries.

func (*SessionCache) Get

func (c *SessionCache) Get(sessionID string) (string, bool)

Get retrieves the auth ID bound to a session, if still valid. Does NOT refresh the TTL on access.

func (*SessionCache) GetAndRefresh

func (c *SessionCache) GetAndRefresh(sessionID string) (string, bool)

GetAndRefresh retrieves the auth ID bound to a session and refreshes TTL on hit. This extends the binding lifetime for active sessions.

func (*SessionCache) Invalidate

func (c *SessionCache) Invalidate(sessionID string)

Invalidate removes a specific session binding.

func (*SessionCache) InvalidateAuth

func (c *SessionCache) InvalidateAuth(authID string)

InvalidateAuth removes all sessions bound to a specific auth ID. Used when an auth becomes unavailable.

func (*SessionCache) Set

func (c *SessionCache) Set(sessionID, authID string)

Set binds a session to an auth ID with TTL refresh.

func (*SessionCache) Stop

func (c *SessionCache) Stop()

Stop terminates the background cleanup goroutine.

type Status

type Status string

Status represents the lifecycle state of an Auth entry.

const (
	// StatusUnknown means the auth state could not be determined.
	StatusUnknown Status = "unknown"
	// StatusActive indicates the auth is valid and ready for execution.
	StatusActive Status = "active"
	// StatusPending indicates the auth is waiting for an external action, such as MFA.
	StatusPending Status = "pending"
	// StatusRefreshing indicates the auth is undergoing a refresh flow.
	StatusRefreshing Status = "refreshing"
	// StatusError indicates the auth is temporarily unavailable due to errors.
	StatusError Status = "error"
	// StatusDisabled marks the auth as intentionally disabled.
	StatusDisabled Status = "disabled"
)

type StoppableSelector

type StoppableSelector interface {
	Selector
	Stop()
}

StoppableSelector is an optional interface for selectors that hold resources. Selectors that implement this interface will have Stop called during shutdown.

type Store

type Store interface {
	// List returns all auth records stored in the backend.
	List(ctx context.Context) ([]*Auth, error)
	// Save persists the provided auth record, replacing any existing one with same ID.
	Save(ctx context.Context, auth *Auth) (string, error)
	// Delete removes the auth record identified by id.
	Delete(ctx context.Context, id string) error
}

Store abstracts persistence of Auth state across restarts.

func GetTokenStore

func GetTokenStore() Store

GetTokenStore returns the globally registered token store.

Jump to

Keyboard shortcuts

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