Documentation
¶
Overview ¶
Package gemini provides Google Gemini CLI integration for Moat.
This package handles:
- Credential injection through proxy configuration
- Configuration file generation for Gemini CLI
- Session management for Gemini runs
- Background OAuth token refresh
Authentication ¶
Gemini supports two authentication methods:
- API Key - Standard API access via x-goog-api-key header
- OAuth - Google OAuth2 access with automatic token refresh
Credentials are handled via proxy injection, never exposed to containers:
- Container receives placeholder credentials in ~/.gemini/
- The Moat proxy intercepts requests and adds real Authorization headers
Important: OAuth vs API Key Use Different API Backends ¶
Gemini CLI routes to different API backends depending on authentication:
- API key mode: generativelanguage.googleapis.com (Google AI SDK)
- OAuth mode: cloudcode-pa.googleapis.com (Cloud Code Private API)
The proxy must inject credentials for the correct host based on auth type.
For OAuth, the proxy also performs token substitution on oauth2.googleapis.com — replacing placeholder tokens in the container's oauth_creds.json with real tokens before requests are forwarded to Google.
Index ¶
- Constants
- func DefaultDependencies() []string
- func GenerateMCPConfig(cfg *config.Config, grants []string) ([]byte, error)
- func HasCredential() bool
- func IsOAuthCredential(cred *provider.Credential) bool
- func NetworkHosts() []string
- func WriteMCPConfig(workspaceDir string, mcpJSON []byte) error
- type Auth
- func (a *Auth) CreateAPIKeyCredential(apiKey string) *provider.Credential
- func (a *Auth) CreateOAuthCredential(accessToken, refreshToken string, expiresAt time.Time) *provider.Credential
- func (a *Auth) PromptForAPIKey() (string, error)
- func (a *Auth) ValidateKey(ctx context.Context, apiKey string) error
- type AuthSettings
- type CLICredentials
- type CLIOAuthToken
- type MCPConfig
- type MCPServer
- type OAuthCreds
- type OAuthError
- type Provider
- func (p *Provider) CanRefresh(cred *provider.Credential) bool
- func (p *Provider) Cleanup(cleanupPath string)
- func (p *Provider) ConfigureProxy(proxy provider.ProxyConfigurer, cred *provider.Credential)
- func (p *Provider) ContainerEnv(cred *provider.Credential) []string
- func (p *Provider) ContainerMounts(cred *provider.Credential, containerHome string) ([]provider.MountConfig, string, error)
- func (p *Provider) Grant(ctx context.Context) (*provider.Credential, error)
- func (p *Provider) ImpliedDependencies() []string
- func (p *Provider) Name() string
- func (p *Provider) PrepareContainer(ctx context.Context, opts provider.PrepareOpts) (*provider.ContainerConfig, error)
- func (p *Provider) Refresh(ctx context.Context, proxy provider.ProxyConfigurer, cred *provider.Credential) (*provider.Credential, error)
- func (p *Provider) RefreshInterval() time.Duration
- func (p *Provider) RegisterCLI(root *cobra.Command)
- type RefreshResult
- type SecuritySettings
- type Settings
- type TokenRefresher
Constants ¶
const ( // GeminiInitMountPath is where the staging directory is mounted in containers. GeminiInitMountPath = "/moat/gemini-init" // GeminiAPIHost is the API endpoint used by Gemini CLI in OAuth mode. // OAuth mode uses the Cloud Code Private API, NOT generativelanguage.googleapis.com. GeminiAPIHost = "cloudcode-pa.googleapis.com" // GeminiAPIKeyHost is the API endpoint used in API key mode. GeminiAPIKeyHost = "generativelanguage.googleapis.com" // GeminiOAuthHost is Google's OAuth2 endpoint. GeminiOAuthHost = "oauth2.googleapis.com" // ProxyInjectedPlaceholder is the placeholder for proxy-injected credentials. ProxyInjectedPlaceholder = credential.ProxyInjectedPlaceholder // OAuthClientID is the public OAuth client ID used by Gemini CLI. // // Source: @google/gemini-cli-core npm package, code_assist/oauth2.ts // npm pack @google/gemini-cli-core && tar xzf *.tgz // grep "OAUTH_CLIENT_ID" package/dist/src/code_assist/oauth2.js // // This is an installed/desktop OAuth application. Per Google's OAuth2 docs: // https://developers.google.com/identity/protocols/oauth2#installed // "The process results in a client ID and, in some cases, a client secret, // which you embed in the source code of your application." OAuthClientID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com" // OAuthClientSecret is the public OAuth client secret used by Gemini CLI. // // Source: same file as OAuthClientID above (code_assist/oauth2.ts). // The Gemini CLI source includes this comment: // "It's ok to save this in git because this is an installed application [...] // In this context, the client secret is obviously not treated as a secret." // // See: https://developers.google.com/identity/protocols/oauth2#installed OAuthClientSecret = "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" // OAuthTokenURL is Google's OAuth2 token endpoint. OAuthTokenURL = "https://oauth2.googleapis.com/token" // ModelsURL is the Gemini API models endpoint for key validation. ModelsURL = "https://generativelanguage.googleapis.com/v1beta/models" // CredentialsFile is the path to Gemini CLI's OAuth credentials relative to home. CredentialsFile = ".gemini/oauth_creds.json" )
Variables ¶
This section is empty.
Functions ¶
func DefaultDependencies ¶
func DefaultDependencies() []string
DefaultDependencies returns the default dependencies for running Gemini CLI.
func GenerateMCPConfig ¶
GenerateMCPConfig generates MCP server configuration for Gemini. Returns nil if no MCP servers are configured.
func HasCredential ¶
func HasCredential() bool
HasCredential returns true if a Gemini credential exists in the store.
func IsOAuthCredential ¶
func IsOAuthCredential(cred *provider.Credential) bool
IsOAuthCredential returns true if the credential is a Gemini OAuth credential.
func NetworkHosts ¶
func NetworkHosts() []string
NetworkHosts returns the list of hosts that Gemini needs network access to. These should be added to the network allow list for containers running Gemini.
func WriteMCPConfig ¶
WriteMCPConfig writes the MCP configuration to the workspace.
Types ¶
type Auth ¶
Auth handles Gemini API key authentication.
func (*Auth) CreateAPIKeyCredential ¶
func (a *Auth) CreateAPIKeyCredential(apiKey string) *provider.Credential
CreateAPIKeyCredential creates a provider.Credential from a validated API key.
func (*Auth) CreateOAuthCredential ¶
func (a *Auth) CreateOAuthCredential(accessToken, refreshToken string, expiresAt time.Time) *provider.Credential
CreateOAuthCredential creates a provider.Credential from OAuth tokens. The access token is stored in Token, the refresh token in Metadata.
func (*Auth) PromptForAPIKey ¶
PromptForAPIKey prompts the user to enter their Gemini API key.
type AuthSettings ¶
type AuthSettings struct {
SelectedType string `json:"selectedType"` // "oauth-personal", "gemini-api-key"
}
AuthSettings holds authentication configuration.
type CLICredentials ¶
type CLICredentials struct {
HomeDir string // Override for testing; empty uses os.UserHomeDir
}
CLICredentials handles extraction of Gemini CLI OAuth credentials.
func (*CLICredentials) CreateMoatCredential ¶
func (c *CLICredentials) CreateMoatCredential(token *CLIOAuthToken) *provider.Credential
CreateMoatCredential creates a provider.Credential from Gemini CLI OAuth token.
func (*CLICredentials) GetCredentials ¶
func (c *CLICredentials) GetCredentials() (*CLIOAuthToken, error)
GetCredentials reads OAuth credentials from ~/.gemini/oauth_creds.json.
func (*CLICredentials) HasCredentials ¶
func (c *CLICredentials) HasCredentials() bool
HasCredentials returns true if Gemini CLI credentials are available.
type CLIOAuthToken ¶
type CLIOAuthToken struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
Scope string `json:"scope"`
TokenType string `json:"token_type"`
ExpiryDate int64 `json:"expiry_date"` // Unix timestamp in milliseconds
}
CLIOAuthToken represents the OAuth credentials stored by Gemini CLI in ~/.gemini/oauth_creds.json.
func (*CLIOAuthToken) ExpiresAtTime ¶
func (t *CLIOAuthToken) ExpiresAtTime() time.Time
ExpiresAtTime returns the expiration time.
func (*CLIOAuthToken) IsExpired ¶
func (t *CLIOAuthToken) IsExpired() bool
IsExpired returns true if the access token has expired.
type MCPServer ¶
type MCPServer struct {
Command string `json:"command"`
Args []string `json:"args,omitempty"`
Env map[string]string `json:"env,omitempty"`
Cwd string `json:"cwd,omitempty"`
}
MCPServer represents a single MCP server configuration.
type OAuthCreds ¶
type OAuthCreds struct {
AccessToken string `json:"access_token"`
Scope string `json:"scope"`
TokenType string `json:"token_type"`
IDToken string `json:"id_token,omitempty"`
ExpiryDate int64 `json:"expiry_date"`
RefreshToken string `json:"refresh_token"`
}
OAuthCreds represents the ~/.gemini/oauth_creds.json file structure.
type OAuthError ¶
type OAuthError struct {
Code string // OAuth error code: "invalid_grant", "invalid_request", etc.
Description string // Human-readable description from Google
}
OAuthError represents an OAuth error from Google's token endpoint. Use errors.As to check for this type and IsRevoked() to detect token revocation.
func (*OAuthError) Error ¶
func (e *OAuthError) Error() string
func (*OAuthError) IsRevoked ¶
func (e *OAuthError) IsRevoked() bool
IsRevoked returns true if the error indicates the refresh token was revoked.
type Provider ¶
type Provider struct{}
Provider implements provider.CredentialProvider and provider.AgentProvider for Google Gemini CLI credentials.
func (*Provider) CanRefresh ¶
func (p *Provider) CanRefresh(cred *provider.Credential) bool
CanRefresh reports whether this credential can be refreshed. OAuth tokens can be refreshed; API keys cannot.
func (*Provider) ConfigureProxy ¶
func (p *Provider) ConfigureProxy(proxy provider.ProxyConfigurer, cred *provider.Credential)
ConfigureProxy sets up proxy headers for Gemini API.
func (*Provider) ContainerEnv ¶
func (p *Provider) ContainerEnv(cred *provider.Credential) []string
ContainerEnv returns environment variables for Gemini.
func (*Provider) ContainerMounts ¶
func (p *Provider) ContainerMounts(cred *provider.Credential, containerHome string) ([]provider.MountConfig, string, error)
ContainerMounts returns mounts needed for Gemini. This method returns empty because Gemini setup uses the staging directory approach instead of direct mounts.
func (*Provider) ImpliedDependencies ¶
ImpliedDependencies returns dependencies implied by the Gemini provider.
func (*Provider) PrepareContainer ¶
func (p *Provider) PrepareContainer(ctx context.Context, opts provider.PrepareOpts) (*provider.ContainerConfig, error)
PrepareContainer sets up staging directories and config files for Gemini CLI. It creates a staging directory with settings.json and optionally oauth_creds.json that will be copied to ~/.gemini at container startup by moat-init.
func (*Provider) Refresh ¶
func (p *Provider) Refresh(ctx context.Context, proxy provider.ProxyConfigurer, cred *provider.Credential) (*provider.Credential, error)
Refresh re-acquires a fresh token and updates the proxy.
func (*Provider) RefreshInterval ¶
RefreshInterval returns how often to attempt refresh. Google OAuth tokens expire after 1 hour; refresh 15 minutes before.
func (*Provider) RegisterCLI ¶
RegisterCLI registers Gemini-related CLI commands. This adds the `moat gemini` command group with subcommands.
type RefreshResult ¶
RefreshResult holds the result of a token refresh.
type SecuritySettings ¶
type SecuritySettings struct {
Auth AuthSettings `json:"auth"`
}
SecuritySettings holds security-related settings.
type Settings ¶
type Settings struct {
Security SecuritySettings `json:"security"`
}
Settings represents Gemini CLI settings.json structure.
type TokenRefresher ¶
type TokenRefresher struct {
TokenURL string // Override for testing; empty uses OAuthTokenURL
HTTPClient *http.Client // Override for testing
}
TokenRefresher refreshes Google OAuth2 access tokens using a refresh token.
func (*TokenRefresher) Refresh ¶
func (r *TokenRefresher) Refresh(ctx context.Context, refreshToken string) (*RefreshResult, error)
Refresh exchanges a refresh token for a new access token.