Documentation
¶
Overview ¶
Package auth handles credential storage and OAuth flows for AI providers.
Credentials are stored in ~/.config/moa/auth.json with mode 0600. Supports both API keys and OAuth tokens (Claude Max).
Index ¶
- func DefaultStorePath() string
- func IsOAuthToken(key string) bool
- func OpenBrowser(url string)
- type Credential
- type OAuthCredentials
- func CompleteXAIDeviceFlow(ctx context.Context, client *http.Client, _ XAIEndpoints, ...) (*OAuthCredentials, error)
- func LoginAnthropic(openURL func(string), promptCode func() (string, error)) (*OAuthCredentials, error)
- func LoginOpenAI(openURL func(string), promptCode func() (string, error)) (*OAuthCredentials, error)
- func LoginXAI(ctx context.Context, openURL func(string), display func(*XAIDeviceCode)) (*OAuthCredentials, error)
- func RefreshAnthropicToken(refreshToken string) (*OAuthCredentials, error)
- func RefreshOpenAIToken(refreshToken string) (*OAuthCredentials, error)
- func RefreshXAIToken(refreshToken string) (*OAuthCredentials, error)
- type Store
- func (s *Store) CredentialKind(provider string) string
- func (s *Store) Get(provider string) (Credential, bool)
- func (s *Store) GetAPIKey(provider string) (key string, isOAuth bool, err error)
- func (s *Store) GetAccountID(provider string) string
- func (s *Store) PeekOAuthToken(provider string) (token string, isOAuth, valid bool)
- func (s *Store) RefreshOAuthIfCurrent(provider, rejected string) (string, error)
- func (s *Store) Remove(provider string) error
- func (s *Store) Set(provider string, cred Credential) error
- type XAIDeviceCode
- type XAIEndpoints
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DefaultStorePath ¶
func DefaultStorePath() string
DefaultStorePath returns the default path for the auth store, or "" when no config directory can be resolved.
func IsOAuthToken ¶
IsOAuthToken returns true if the given key looks like an OAuth token rather than a standard API key. Detects Anthropic OAuth (sk-ant-oat) and JWT tokens (three dot-separated segments, as used by OpenAI OAuth).
Types ¶
type Credential ¶
type Credential struct {
Type string `json:"type"` // "api_key" or "oauth"
Key string `json:"key,omitempty"` // API key (type=api_key)
Access string `json:"access,omitempty"` // OAuth access token (type=oauth)
Refresh string `json:"refresh,omitempty"` // OAuth refresh token (type=oauth)
Expires int64 `json:"expires,omitempty"` // OAuth token expiry (unix ms) (type=oauth)
AccountID string `json:"account_id,omitempty"` // Provider-specific account ID (e.g., OpenAI chatgpt_account_id)
}
Credential represents a stored credential for a provider.
type OAuthCredentials ¶
type OAuthCredentials struct {
Access string `json:"access"`
Refresh string `json:"refresh"`
Expires int64 `json:"expires"` // Unix milliseconds
AccountID string `json:"account_id,omitempty"` // OpenAI chatgpt_account_id
}
OAuthCredentials holds the result of an OAuth login/refresh.
func CompleteXAIDeviceFlow ¶ added in v0.26.0
func CompleteXAIDeviceFlow(ctx context.Context, client *http.Client, _ XAIEndpoints, device *XAIDeviceCode) (*OAuthCredentials, error)
CompleteXAIDeviceFlow uses the endpoint and expiry captured at authorization; it never rediscovers metadata or restarts the device-code lifetime.
func LoginAnthropic ¶
func LoginAnthropic(openURL func(string), promptCode func() (string, error)) (*OAuthCredentials, error)
LoginAnthropic runs the Anthropic OAuth PKCE flow (device code style): 1. Generate PKCE verifier + challenge 2. Open browser to Anthropic authorize URL 3. User approves and sees a code on Anthropic's callback page 4. User pastes the code back into the CLI 5. Exchange code for tokens
promptCode is called to get the authorization code from the user. It receives the auth URL (for display) and should return the pasted code string.
func LoginOpenAI ¶
func LoginOpenAI(openURL func(string), promptCode func() (string, error)) (*OAuthCredentials, error)
LoginOpenAI runs the OpenAI PKCE OAuth flow with a local callback server. Returns credentials including the accountId extracted from the JWT.
openURL is called to open the browser. promptCode is the fallback if the local server doesn't receive the callback.
func LoginXAI ¶ added in v0.26.0
func LoginXAI(ctx context.Context, openURL func(string), display func(*XAIDeviceCode)) (*OAuthCredentials, error)
func RefreshAnthropicToken ¶
func RefreshAnthropicToken(refreshToken string) (*OAuthCredentials, error)
RefreshAnthropicToken refreshes an expired OAuth token.
func RefreshOpenAIToken ¶
func RefreshOpenAIToken(refreshToken string) (*OAuthCredentials, error)
RefreshOpenAIToken refreshes an expired OpenAI OAuth token.
func RefreshXAIToken ¶ added in v0.26.0
func RefreshXAIToken(refreshToken string) (*OAuthCredentials, error)
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store manages credentials on disk.
func (*Store) CredentialKind ¶ added in v0.26.0
CredentialKind reports the credential origin without inspecting token contents. Environment values are always API keys, including JWT-shaped xAI values, so transport selection cannot be confused by token syntax.
func (*Store) Get ¶
func (s *Store) Get(provider string) (Credential, bool)
Get retrieves a credential for a provider.
func (*Store) GetAPIKey ¶
GetAPIKey resolves the API key for a provider. Priority:
- Environment variable (ANTHROPIC_API_KEY, etc.)
- OAuth token from store (auto-refreshed if expired)
- API key from store
Returns the key and whether it's an OAuth token.
func (*Store) GetAccountID ¶
GetAccountID returns the stored account ID for a provider (e.g., OpenAI chatgpt_account_id).
func (*Store) PeekOAuthToken ¶
PeekOAuthToken returns the current OAuth access token for a provider WITHOUT triggering a refresh. It is for read-only, best-effort callers (e.g. the plan usage widget) that must never rotate the shared refresh token.
- isOAuth is true when an OAuth credential is in use for the provider.
- valid is true only when a non-expired access token is available.
When isOAuth is true but valid is false, the token has expired: the caller should treat usage as temporarily unavailable rather than refresh, and let a real API call renew the token on demand.
func (*Store) RefreshOAuthIfCurrent ¶ added in v0.26.0
RefreshOAuthIfCurrent reactively rotates an OAuth token that a consumer API rejected. If another request already rotated it, that newer token is reused. It deliberately never considers environment variables: those are API keys.
type XAIDeviceCode ¶ added in v0.26.0
type XAIDeviceCode struct {
DeviceCode string
UserCode string
VerificationURI string
VerificationURIComplete string
ExpiresIn time.Duration
Interval time.Duration
// contains filtered or unexported fields
}
XAIDeviceCode is the user-facing part of an RFC 8628 authorization request.
func StartXAIDeviceFlow ¶ added in v0.26.0
func StartXAIDeviceFlow(ctx context.Context, client *http.Client, endpoints XAIEndpoints) (*XAIDeviceCode, error)
type XAIEndpoints ¶ added in v0.26.0
type XAIEndpoints struct {
DiscoveryURL string
AllowedHosts []string
AllowedIssuers []string
AllowHTTP bool
Wait func(context.Context, time.Duration) error
Now func() time.Time
}
XAIEndpoints is test configuration for the xAI OIDC client. Production must leave it empty: that pins discovery, issuer, and endpoints to auth.x.ai. A non-default endpoint requires an explicit host allowlist. AllowHTTP and Wait are intended only for local tests.