oauth

package
v1.18.3 Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package oauth provides OAuth 2.0 authentication for LLM providers. It supports PKCE flow (Google Gemini, ChatGPT) and Device Code flow (Qwen, MiniMax).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FindAvailablePort

func FindAvailablePort(startPort int) (int, error)

FindAvailablePort finds an available port on localhost.

func VerifyChallenge

func VerifyChallenge(verifier, expectedChallenge string) bool

VerifyChallenge verifies that a verifier produces the expected challenge. This is useful for testing and validation.

Types

type CallbackResult

type CallbackResult struct {
	// Code is the authorization code (on success)
	Code string

	// State is the state parameter from the callback
	State string

	// Error contains the error message (on failure)
	Error string

	// ErrorDescription provides more details about the error
	ErrorDescription string
}

CallbackResult contains the result of an OAuth callback.

type CallbackServer

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

CallbackServer handles OAuth callbacks on a local HTTP server.

func NewCallbackServer

func NewCallbackServer(port int, state string, timeout time.Duration, logger *slog.Logger) *CallbackServer

NewCallbackServer creates a new callback server.

func (*CallbackServer) CallbackURL

func (s *CallbackServer) CallbackURL() string

CallbackURL returns the callback URL for this server.

func (*CallbackServer) Close

func (s *CallbackServer) Close() error

Close stops the callback server.

func (*CallbackServer) Port

func (s *CallbackServer) Port() int

Port returns the port the server is listening on.

func (*CallbackServer) Start

func (s *CallbackServer) Start() error

Start starts the callback server.

func (*CallbackServer) WaitForCallback

func (s *CallbackServer) WaitForCallback() (*CallbackResult, error)

WaitForCallback waits for the OAuth callback or timeout.

func (*CallbackServer) WaitForCallbackWithContext

func (s *CallbackServer) WaitForCallbackWithContext(ctx context.Context) (*CallbackResult, error)

WaitForCallbackWithContext waits for the OAuth callback with context support.

type Config

type Config struct {
	// Providers maps provider names to their configurations
	Providers map[string]ProviderConfig `yaml:"providers" json:"providers"`
}

Config contains OAuth configuration for all providers.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns the default OAuth configuration.

type DeviceCodeError

type DeviceCodeError struct {
	Code             string // "authorization_pending", "slow_down", etc.
	ErrorDescription string
}

DeviceCodeError represents an error from the device code flow.

func (*DeviceCodeError) Error

func (e *DeviceCodeError) Error() string

func (*DeviceCodeError) IsPending

func (e *DeviceCodeError) IsPending() bool

IsPending returns true if the error indicates authorization is still pending.

type DeviceCodeFlow

type DeviceCodeFlow struct {

	// DeviceCodeURL is the endpoint to request a device code
	DeviceCodeURL string

	// TokenURL is the endpoint to exchange device code for tokens
	TokenURL string

	// ClientID is the OAuth client ID
	ClientID string

	// Scopes are the OAuth scopes to request
	Scopes []string
	// contains filtered or unexported fields
}

DeviceCodeFlow handles OAuth device code flow for providers like Qwen and MiniMax.

func NewDeviceCodeFlow

func NewDeviceCodeFlow(deviceCodeURL, tokenURL, clientID string, scopes []string, logger *slog.Logger) *DeviceCodeFlow

NewDeviceCodeFlow creates a new device code flow handler.

func (*DeviceCodeFlow) ExchangePKCE

func (d *DeviceCodeFlow) ExchangePKCE(ctx context.Context, code, verifier, redirectURI string) (*OAuthCredential, error)

ExchangePKCE exchanges an authorization code for tokens using PKCE. This is used by providers that support PKCE flow (like Qwen Portal).

func (*DeviceCodeFlow) Poll

func (d *DeviceCodeFlow) Poll(ctx context.Context, deviceCode string, interval time.Duration) (*OAuthCredential, error)

Poll polls the token endpoint until the user completes verification. It respects the polling interval and handles the "authorization_pending" response.

func (*DeviceCodeFlow) RefreshToken

func (d *DeviceCodeFlow) RefreshToken(ctx context.Context, refreshToken string) (*OAuthCredential, error)

RefreshToken refreshes an access token using a refresh token.

func (*DeviceCodeFlow) Start

Start initiates the device code flow and returns the device code response.

type DeviceCodeProvider

type DeviceCodeProvider interface {
	OAuthProvider

	// StartDeviceFlow initiates a device code flow
	StartDeviceFlow(ctx context.Context) (*DeviceCodeResponse, error)

	// PollForToken polls the token endpoint until the user completes verification
	PollForToken(ctx context.Context, deviceCode string, interval time.Duration) (*OAuthCredential, error)
}

DeviceCodeProvider extends OAuthProvider with device code flow methods.

type DeviceCodeResponse

type DeviceCodeResponse struct {
	// DeviceCode is used to poll for the token
	DeviceCode string `json:"device_code"`

	// UserCode is displayed to the user for verification
	UserCode string `json:"user_code"`

	// VerificationURI is the URL the user visits to enter the code
	VerificationURI string `json:"verification_uri"`

	// VerificationURIComplete includes the user code in the URL (optional)
	VerificationURIComplete string `json:"verification_uri_complete,omitempty"`

	// ExpiresIn is the time in seconds until the device code expires
	ExpiresIn int `json:"expires_in"`

	// Interval is the polling interval in seconds
	Interval int `json:"interval"`
}

DeviceCodeResponse represents the response from a device code authorization request.

type HubAdapter added in v1.13.0

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

HubAdapter implements OAuthManager by delegating to an OAuth Hub instance. It maps DevClaw provider names to Hub connection IDs.

func NewHubAdapter added in v1.13.0

func NewHubAdapter(cfg HubAdapterConfig) (*HubAdapter, error)

NewHubAdapter creates a new OAuth Hub adapter.

func (*HubAdapter) GetValidToken added in v1.13.0

func (h *HubAdapter) GetValidToken(provider string) (*OAuthCredential, error)

GetValidToken returns a valid access token for the given provider. It calls the Hub's /api/v1/token/get endpoint.

func (*HubAdapter) SaveCredential added in v1.13.0

func (h *HubAdapter) SaveCredential(_ *OAuthCredential) error

SaveCredential is a no-op for Hub mode — the Hub manages token storage.

type HubAdapterConfig added in v1.13.0

type HubAdapterConfig struct {
	HubURL       string
	APIKey       string
	APIKeyEnvVar string
	Logger       *slog.Logger
}

HubAdapterConfig configures the Hub adapter.

type LoginResult

type LoginResult struct {
	// Credential is the OAuth credential (on success)
	Credential *OAuthCredential

	// Provider is the provider name
	Provider string

	// Error contains any error that occurred
	Error error

	// Warning contains non-fatal warnings (e.g., experimental feature)
	Warning string
}

LoginResult contains the result of an OAuth login attempt.

type OAuthCredential

type OAuthCredential struct {
	// Provider identifies which OAuth provider this credential belongs to
	// (e.g., "gemini", "chatgpt", "qwen", "minimax")
	Provider string `json:"provider"`

	// AccessToken is the OAuth access token used for API requests
	AccessToken string `json:"access_token"`

	// RefreshToken is used to obtain new access tokens
	RefreshToken string `json:"refresh_token"`

	// ExpiresAt is when the access token expires
	ExpiresAt time.Time `json:"expires_at"`

	// Email is the user's email associated with the OAuth account
	Email string `json:"email,omitempty"`

	// ClientID is the OAuth client ID used for this credential
	ClientID string `json:"client_id,omitempty"`

	// Metadata contains provider-specific data (e.g., project IDs, regions)
	Metadata map[string]string `json:"metadata,omitempty"`
}

OAuthCredential represents stored OAuth tokens for a provider.

func (*OAuthCredential) GetAccessToken

func (c *OAuthCredential) GetAccessToken() string

GetAccessToken returns the access token (implements interface for LLMClient).

func (*OAuthCredential) IsExpired

func (c *OAuthCredential) IsExpired(buffer time.Duration) bool

IsExpired returns true if the credential has expired or will expire within the buffer.

func (*OAuthCredential) IsValid

func (c *OAuthCredential) IsValid() bool

IsValid returns true if the credential has a valid access token that hasn't expired.

type OAuthFlowType

type OAuthFlowType string

OAuthFlowType indicates the type of OAuth flow to use.

const (
	// FlowPKCE indicates a PKCE-based OAuth flow with local callback
	FlowPKCE OAuthFlowType = "pkce"

	// FlowDeviceCode indicates a device code flow for CLI/headless environments
	FlowDeviceCode OAuthFlowType = "device_code"
)

type OAuthProvider

type OAuthProvider interface {
	// Name returns the provider identifier (e.g., "gemini", "chatgpt")
	Name() string

	// Label returns a human-readable provider name
	Label() string

	// AuthURL returns the authorization URL for the OAuth flow
	// state is a random string for CSRF protection
	// challenge is the PKCE code challenge (for PKCE flows)
	AuthURL(state, challenge string) string

	// TokenURL returns the token exchange endpoint
	TokenURL() string

	// ExchangeCode exchanges an authorization code for tokens
	// code is the authorization code from the callback
	// verifier is the PKCE code verifier
	ExchangeCode(ctx context.Context, code, verifier string) (*OAuthCredential, error)

	// RefreshToken obtains a new access token using a refresh token
	RefreshToken(ctx context.Context, refreshToken string) (*OAuthCredential, error)

	// Scopes returns the OAuth scopes required for this provider
	Scopes() []string

	// SupportsPKCE returns true if the provider supports PKCE flow
	SupportsPKCE() bool

	// SupportsDeviceCode returns true if the provider supports device code flow
	SupportsDeviceCode() bool
}

OAuthProvider defines the interface for OAuth providers.

type PKCEPair

type PKCEPair struct {
	// Verifier is the random string used to verify the OAuth flow
	Verifier string `json:"verifier"`

	// Challenge is the SHA256 hash of the verifier, base64url encoded
	Challenge string `json:"challenge"`
}

PKCEPair contains the PKCE verifier and challenge for OAuth flows.

func GeneratePKCE

func GeneratePKCE() (*PKCEPair, error)

GeneratePKCE creates a new PKCE verifier and challenge pair. The verifier is a cryptographically random string. The challenge is the SHA256 hash of the verifier, base64url encoded.

type ProviderConfig

type ProviderConfig struct {
	// Enabled indicates if this provider is available
	Enabled bool `yaml:"enabled" json:"enabled"`

	// ClientID is the OAuth client ID (optional, some providers have defaults)
	ClientID string `yaml:"client_id,omitempty" json:"client_id,omitempty"`

	// ClientSecret is the OAuth client secret (optional, rarely needed)
	ClientSecret string `yaml:"client_secret,omitempty" json:"client_secret,omitempty"`

	// RedirectPort is the local port for OAuth callbacks (PKCE flow)
	RedirectPort int `yaml:"redirect_port,omitempty" json:"redirect_port,omitempty"`

	// Region is the provider region (e.g., "global" or "cn" for MiniMax)
	Region string `yaml:"region,omitempty" json:"region,omitempty"`
}

ProviderConfig contains configuration for an OAuth provider.

type TokenManager

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

TokenManager manages OAuth tokens with automatic refresh.

func NewTokenManager

func NewTokenManager(dataDir string, logger *slog.Logger) (*TokenManager, error)

NewTokenManager creates a new token manager.

func (*TokenManager) DeleteCredential

func (tm *TokenManager) DeleteCredential(provider string) error

DeleteCredential removes a credential for a provider.

func (*TokenManager) GetCredential

func (tm *TokenManager) GetCredential(provider string) (*OAuthCredential, error)

GetCredential returns the credential for a provider.

func (*TokenManager) GetStatus

func (tm *TokenManager) GetStatus() map[string]TokenStatus

GetStatus returns the status of all provider tokens.

func (*TokenManager) GetValidToken

func (tm *TokenManager) GetValidToken(provider string) (*OAuthCredential, error)

GetValidToken returns a valid access token, refreshing if necessary.

func (*TokenManager) GetValidTokenInterface

func (tm *TokenManager) GetValidTokenInterface(provider string) (interface{}, error)

GetValidTokenInterface returns a valid token as interface{} (for LLMClient compatibility).

func (*TokenManager) ListProviders

func (tm *TokenManager) ListProviders() []string

ListProviders returns the list of providers with credentials.

func (*TokenManager) NeedsLogin

func (tm *TokenManager) NeedsLogin(provider string) bool

NeedsLogin returns true if a provider needs to log in (no valid credential).

func (*TokenManager) Refresh

func (tm *TokenManager) Refresh(provider string) (*OAuthCredential, error)

Refresh forces a refresh of a provider's token.

func (*TokenManager) RegisterProvider

func (tm *TokenManager) RegisterProvider(provider OAuthProvider)

RegisterProvider registers an OAuth provider for token refresh.

func (*TokenManager) SaveCredential

func (tm *TokenManager) SaveCredential(cred *OAuthCredential) error

SaveCredential saves a credential for a provider.

func (*TokenManager) StartAutoRefresh

func (tm *TokenManager) StartAutoRefresh()

StartAutoRefresh starts the background token refresh goroutine.

func (*TokenManager) Stop

func (tm *TokenManager) Stop()

Stop stops the background refresh goroutine.

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in"`
	Scope        string `json:"scope,omitempty"`
	IDToken      string `json:"id_token,omitempty"`
}

TokenResponse represents the response from a token exchange request.

type TokenStatus

type TokenStatus struct {
	Provider  string        `json:"provider"`
	Status    string        `json:"status"` // valid, expiring_soon, expired, unknown
	Email     string        `json:"email,omitempty"`
	ExpiresIn time.Duration `json:"expires_in,omitempty"`
	HasToken  bool          `json:"has_token"`
}

TokenStatus represents the status of a provider's token.

type TokenStore

type TokenStore struct {
	Version   int                         `json:"version"`
	Providers map[string]*OAuthCredential `json:"providers"`
}

TokenStore is the on-disk format for OAuth tokens.

Directories

Path Synopsis
Package providers implements OAuth providers for various LLM services.
Package providers implements OAuth providers for various LLM services.

Jump to

Keyboard shortcuts

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