credential

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Feb 11, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package credential provides credential management for Moat.

Package credential provides credential management for Moat.

Package credential provides secure credential storage and retrieval.

Package credential provides secure credential storage and retrieval.

Index

Constants

View Source
const (
	// ClaudeCodeKeychainService is the macOS Keychain service name for Claude Code credentials.
	ClaudeCodeKeychainService = "Claude Code-credentials"

	// ClaudeCredentialsFile is the relative path to Claude's credentials file.
	ClaudeCredentialsFile = ".claude/.credentials.json"
)
View Source
const GitHubTokenPlaceholder = "ghp_moatProxyInjectedPlaceholder000000000000"

GitHubTokenPlaceholder is a placeholder that looks like a valid GitHub personal access token.

The gh CLI validates token format locally before making requests. Real GitHub PATs use the format ghp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (ghp_ prefix + 36 base62 characters, 40 total).

This format-valid placeholder is necessary because: - gh CLI checks GH_TOKEN format before making API calls - Tools like Claude Code's footer use gh CLI to fetch PR status - Without a valid-looking token, gh CLI rejects it and may prompt for auth

The proxy intercepts all GitHub HTTPS traffic and injects the real token via Authorization headers, so this placeholder never reaches GitHub's servers.

View Source
const JWTPlaceholder = "" /* 135-byte string literal not displayed */

JWTPlaceholder is a basic placeholder JWT for format validation only. Use GenerateIDTokenPlaceholder for Codex CLI which needs account_id in claims.

View Source
const MetaKeyTokenSource = "token_source"

MetaKeyTokenSource is the metadata key for recording how a token was obtained. Provider packages define the values (e.g., "cli", "env", "pat").

View Source
const OpenAIAPIKeyPlaceholder = "sk-moat-proxy-injected-placeholder-0000000000000000000000000000000000000000"

OpenAIAPIKeyPlaceholder is a placeholder that looks like a valid OpenAI API key. Some tools validate the API key format locally before making requests. Using a valid-looking placeholder bypasses these checks while still allowing the proxy to inject the real key at the network layer.

View Source
const ProxyInjectedPlaceholder = "moat-proxy-injected"

ProxyInjectedPlaceholder is a placeholder value for credentials that will be injected by the Moat proxy at runtime. The actual credential never reaches the container; instead, the proxy intercepts requests and adds the real Authorization header. This placeholder signals to tools that a credential is expected without exposing the actual value.

Variables

This section is empty.

Functions

func DefaultEncryptionKey

func DefaultEncryptionKey() ([]byte, error)

DefaultEncryptionKey retrieves the encryption key from secure storage. Uses system keychain when available, falls back to file-based storage.

func DefaultStoreDir

func DefaultStoreDir() string

DefaultStoreDir returns the default credential store directory.

func GenerateAccessTokenPlaceholder

func GenerateAccessTokenPlaceholder(accountID string) string

GenerateAccessTokenPlaceholder creates a JWT-formatted access token placeholder. The Codex CLI also validates the access_token as a JWT and extracts claims from it. This placeholder mirrors the structure of a real OpenAI access token.

func GenerateIDTokenPlaceholder

func GenerateIDTokenPlaceholder(accountID string) string

GenerateIDTokenPlaceholder creates a JWT-formatted placeholder with the account_id embedded in the claims. This is required for Codex CLI which extracts the chatgpt_account_id from the id_token's JWT claims locally before making API calls.

The generated JWT has: - Header: {"alg":"RS256","typ":"JWT"} - Payload: {"sub":"moat-placeholder","exp":<future>,"https://api.openai.com/auth":{"chatgpt_account_id":"<account_id>"}} - Signature: placeholder (not cryptographically valid)

The signature is not valid, but Codex CLI only decodes the claims - it doesn't verify the signature locally (that's done server-side).

func ImpliedDependencies

func ImpliedDependencies(grants []string) []string

ImpliedDependencies returns the dependencies implied by a list of grants. For example, a "github" grant implies "gh" and "git" dependencies.

func IsKnownProvider

func IsKnownProvider(p Provider) bool

IsKnownProvider returns true if the provider is a known credential provider.

func IsOAuthToken

func IsOAuthToken(token string) bool

IsOAuthToken returns true if the token appears to be a Claude Code OAuth token.

This uses a prefix-based heuristic: OAuth tokens from Claude Code start with "sk-ant-oat" (Anthropic OAuth Token). This prefix format is based on observed token structure as of 2025. If Anthropic changes their token format in the future, this function may need to be updated.

Note: API keys typically start with "sk-ant-api" for comparison.

func RegisterImpliedDeps

func RegisterImpliedDeps(provider Provider, fn func() []string)

RegisterImpliedDeps registers an implied dependencies function for a provider. This is typically called from init() functions in provider packages.

func RegisterProviderSetup

func RegisterProviderSetup(provider Provider, setup ProviderSetup)

RegisterProviderSetup registers a ProviderSetup for a provider. This is typically called from init() functions in provider packages.

func ValidateGrant

func ValidateGrant(grant string) error

ValidateGrant validates a grant string and returns an error if invalid. Grants must be a known provider, optionally with a scope suffix (e.g., "github:repo").

Types

type AnthropicAuth

type AnthropicAuth struct {
	HTTPClient *http.Client // Optional; uses http.DefaultClient if nil

	// APIURL allows overriding the endpoint for testing.
	APIURL string
}

AnthropicAuth handles Anthropic API key authentication.

func (*AnthropicAuth) CreateCredential

func (a *AnthropicAuth) CreateCredential(apiKey string) Credential

CreateCredential creates a Credential from a validated API key.

func (*AnthropicAuth) PromptForAPIKey

func (a *AnthropicAuth) PromptForAPIKey() (string, error)

PromptForAPIKey prompts the user to enter their Anthropic API key.

func (*AnthropicAuth) ValidateKey

func (a *AnthropicAuth) ValidateKey(ctx context.Context, apiKey string) error

ValidateKey validates an Anthropic API key by making a minimal API request. Returns nil if the key is valid, or an error describing the problem.

type ClaudeCodeCredentials

type ClaudeCodeCredentials struct{}

ClaudeCodeCredentials handles extraction of Claude Code OAuth credentials.

func (*ClaudeCodeCredentials) CreateCredentialFromOAuth

func (c *ClaudeCodeCredentials) CreateCredentialFromOAuth(token *ClaudeOAuthToken) Credential

CreateCredentialFromOAuth creates a Moat Credential from Claude Code OAuth token.

func (*ClaudeCodeCredentials) GetClaudeCodeCredentials

func (c *ClaudeCodeCredentials) GetClaudeCodeCredentials() (*ClaudeOAuthToken, error)

GetClaudeCodeCredentials attempts to retrieve Claude Code OAuth credentials. It tries the following sources in order: 1. macOS Keychain (if on macOS) 2. ~/.claude/.credentials.json file

Returns the credentials if found, or an error describing what went wrong.

func (*ClaudeCodeCredentials) HasClaudeCodeCredentials

func (c *ClaudeCodeCredentials) HasClaudeCodeCredentials() bool

HasClaudeCodeCredentials checks if Claude Code credentials are available.

type ClaudeOAuthCredentials

type ClaudeOAuthCredentials struct {
	ClaudeAiOauth *ClaudeOAuthToken `json:"claudeAiOauth,omitempty"`
}

ClaudeOAuthCredentials represents the OAuth credentials stored by Claude Code.

type ClaudeOAuthToken

type ClaudeOAuthToken struct {
	AccessToken      string   `json:"accessToken"`
	RefreshToken     string   `json:"refreshToken"`
	ExpiresAt        int64    `json:"expiresAt"` // Unix timestamp in milliseconds
	Scopes           []string `json:"scopes"`
	SubscriptionType string   `json:"subscriptionType,omitempty"`
	RateLimitTier    string   `json:"rateLimitTier,omitempty"`
}

ClaudeOAuthToken represents an individual OAuth token from Claude Code.

func (*ClaudeOAuthToken) ExpiresAtTime

func (t *ClaudeOAuthToken) ExpiresAtTime() time.Time

ExpiresAtTime returns the expiration time as a time.Time.

func (*ClaudeOAuthToken) IsExpired

func (t *ClaudeOAuthToken) IsExpired() bool

IsExpired returns true if the token has expired.

type Credential

type Credential struct {
	Provider  Provider          `json:"provider"`
	Token     string            `json:"token"`
	Scopes    []string          `json:"scopes,omitempty"`
	ExpiresAt time.Time         `json:"expires_at,omitempty"`
	CreatedAt time.Time         `json:"created_at"`
	Metadata  map[string]string `json:"metadata,omitempty"` // Provider-specific extra data
}

Credential represents a stored credential.

func (*Credential) GetCreatedAt

func (c *Credential) GetCreatedAt() time.Time

GetCreatedAt implements ProviderCredential.

func (*Credential) GetExpiresAt

func (c *Credential) GetExpiresAt() time.Time

GetExpiresAt implements ProviderCredential.

func (*Credential) GetMetadata

func (c *Credential) GetMetadata() map[string]string

GetMetadata implements ProviderCredential.

func (*Credential) GetProvider

func (c *Credential) GetProvider() string

GetProvider implements ProviderCredential.

func (*Credential) GetScopes

func (c *Credential) GetScopes() []string

GetScopes implements ProviderCredential.

func (*Credential) GetToken

func (c *Credential) GetToken() string

GetToken implements ProviderCredential.

type FileStore

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

FileStore implements Store using encrypted files.

func NewFileStore

func NewFileStore(dir string, key []byte) (*FileStore, error)

NewFileStore creates a file-based credential store. key must be 32 bytes for AES-256.

func (*FileStore) AddSSHMapping

func (s *FileStore) AddSSHMapping(mapping SSHMapping) error

AddSSHMapping adds or updates an SSH host-to-key mapping.

func (*FileStore) Delete

func (s *FileStore) Delete(provider Provider) error

Delete removes a credential for the given provider.

func (*FileStore) Get

func (s *FileStore) Get(provider Provider) (*Credential, error)

Get retrieves a credential for the given provider.

func (*FileStore) GetSSHMappings

func (s *FileStore) GetSSHMappings() ([]SSHMapping, error)

GetSSHMappings returns all SSH host-to-key mappings.

func (*FileStore) GetSSHMappingsForHosts

func (s *FileStore) GetSSHMappingsForHosts(hosts []string) ([]SSHMapping, error)

GetSSHMappingsForHosts returns mappings for the specified hosts.

func (*FileStore) List

func (s *FileStore) List() ([]Credential, error)

List returns all stored credentials.

func (*FileStore) RemoveSSHMapping

func (s *FileStore) RemoveSSHMapping(host string) error

RemoveSSHMapping removes an SSH mapping for a host.

func (*FileStore) Save

func (s *FileStore) Save(cred Credential) error

Save stores a credential encrypted on disk.

type OAuthCredentialInfo

type OAuthCredentialInfo struct {
	AccessToken string
	ExpiresAt   time.Time
	Scopes      []string
}

OAuthCredentialInfo holds information extracted from an OAuth credential for creating credential files.

type OpenAIAuth

type OpenAIAuth struct {
	HTTPClient *http.Client // Optional; uses http.DefaultClient if nil

	// APIURL allows overriding the endpoint for testing.
	APIURL string
}

OpenAIAuth handles OpenAI API key authentication.

func (*OpenAIAuth) CreateCredential

func (a *OpenAIAuth) CreateCredential(apiKey string) Credential

CreateCredential creates a Credential from a validated API key.

func (*OpenAIAuth) PromptForAPIKey

func (a *OpenAIAuth) PromptForAPIKey() (string, error)

PromptForAPIKey prompts the user to enter their OpenAI API key.

func (*OpenAIAuth) ValidateKey

func (a *OpenAIAuth) ValidateKey(ctx context.Context, apiKey string) error

ValidateKey validates an OpenAI API key by making a minimal API request. Returns nil if the key is valid, or an error describing the problem.

type Provider

type Provider string

Provider identifies a credential provider (github, aws, etc.)

const (
	ProviderGitHub    Provider = "github"
	ProviderAWS       Provider = "aws"
	ProviderAnthropic Provider = "anthropic"
	ProviderOpenAI    Provider = "openai"
	ProviderGemini    Provider = "gemini"
	ProviderNpm       Provider = "npm"
)

func KnownProviders

func KnownProviders() []Provider

KnownProviders returns a list of all known credential providers.

func ParseGrantProvider

func ParseGrantProvider(grant string) Provider

ParseGrantProvider extracts the provider from a grant string. Grants can be "provider" or "provider:scope" format. For example, "github:repo" returns ProviderGitHub.

type ProviderCredential

type ProviderCredential interface {
	GetProvider() string
	GetToken() string
	GetScopes() []string
	GetExpiresAt() time.Time
	GetCreatedAt() time.Time
	GetMetadata() map[string]string
}

ProviderCredential is a minimal interface for provider.Credential conversion. This allows passing credentials to the new provider package without import cycles.

type ProviderResult

type ProviderResult struct {
	// Env contains environment variables to add to the container.
	Env []string
	// Mounts contains mount configurations for the container.
	Mounts []container.MountConfig
	// CleanupPath is a path to clean up when the run ends (optional).
	CleanupPath string
}

ProviderResult holds the result of configuring a provider.

type ProviderSetup

type ProviderSetup interface {
	// Provider returns the provider identifier.
	Provider() Provider

	// ConfigureProxy sets up proxy headers for this credential.
	ConfigureProxy(p ProxyConfigurer, cred *Credential)

	// ContainerEnv returns environment variables to set in the container.
	ContainerEnv(cred *Credential) []string

	// ContainerMounts returns mounts needed for this credential.
	// The containerHome parameter is the home directory inside the container.
	// Returns the mounts and an optional cleanup directory path.
	ContainerMounts(cred *Credential, containerHome string) ([]container.MountConfig, string, error)

	// Cleanup is called when the run ends to clean up any resources.
	// The cleanupPath is the path returned by ContainerMounts.
	Cleanup(cleanupPath string)
}

ProviderSetup configures a credential provider for use in a container run. Each provider (GitHub, Anthropic, etc.) implements this interface to handle its specific proxy configuration, environment variables, and container mounts.

func GetProviderSetup

func GetProviderSetup(provider Provider) ProviderSetup

GetProviderSetup returns the ProviderSetup for a given provider. Returns nil if the provider doesn't have a registered setup. Provider packages register their setups via init() using RegisterProviderSetup.

type ProxyConfigurer

type ProxyConfigurer interface {
	// SetCredential sets an Authorization header for a host.
	SetCredential(host, value string)
	// SetCredentialHeader sets a custom header for a host.
	SetCredentialHeader(host, headerName, headerValue string)
	// SetCredentialWithGrant sets a credential header with grant info for logging.
	SetCredentialWithGrant(host, headerName, headerValue, grant string)
	// AddExtraHeader adds an additional header to inject for a host.
	AddExtraHeader(host, headerName, headerValue string)
	// AddResponseTransformer registers a response transformer for a host.
	// Transformers are called in registration order after the response is received.
	AddResponseTransformer(host string, transformer ResponseTransformer)
	// RemoveRequestHeader removes a client-sent header before forwarding.
	// Used when injected credentials conflict with client headers.
	RemoveRequestHeader(host, headerName string)
	// SetTokenSubstitution replaces placeholder tokens with real tokens in both
	// Authorization headers and request bodies for a specific host.
	// Body substitution is limited to 64KB requests to avoid memory issues.
	SetTokenSubstitution(host, placeholder, realToken string)
}

type ResponseTransformer

type ResponseTransformer func(req, resp interface{}) (interface{}, bool)

ProxyConfigurer is the interface for configuring proxy credentials. This avoids importing the proxy package directly. ResponseTransformer modifies HTTP responses for a host. It receives the request and response as interface{} to avoid circular dependencies. Cast to *http.Request and *http.Response in the transformer implementation. Returns the modified response and true if transformed, or original response and false otherwise.

Note on body handling: Transformers are called BEFORE body capture for logging. If you need to inspect the response body, read it within the transformer and return a new response with a fresh body reader. The original body is not rewound after reading.

type SSHMapping

type SSHMapping struct {
	Host           string    `json:"host"`
	KeyFingerprint string    `json:"key_fingerprint"`
	KeyPath        string    `json:"key_path,omitempty"`
	CreatedAt      time.Time `json:"created_at"`
}

SSHMapping maps a host to an SSH key fingerprint.

type Store

type Store interface {
	Save(cred Credential) error
	Get(provider Provider) (*Credential, error)
	Delete(provider Provider) error
	List() ([]Credential, error)
}

Store defines the credential storage interface.

Directories

Path Synopsis
Package keyring provides secure storage for the credential encryption key.
Package keyring provides secure storage for the credential encryption key.

Jump to

Keyboard shortcuts

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