Documentation
¶
Index ¶
- Constants
- Variables
- func GetAuthFilePath() (string, error)
- func GetLoggedInEndpoints() []string
- func GetUserID(ep string) string
- func IsAuthRequired() bool
- func IsAuthenticated() (bool, error)
- func IsAuthenticatedForEndpoint(endpoint string) (bool, error)
- func IsCloudEnabled() bool
- func IsMemoryEnabled() bool
- func IsPostMVPEnabled() bool
- func IsValidServerSessionID(id string) bool
- func ListEndpoints() ([]string, error)
- func Login(ctx context.Context, deviceCode *DeviceCodeResponse, ...) error
- func NewServerSessionID() string
- func RemoveToken() error
- func RemoveTokenForEndpoint(ep string) error
- func RequireAuth() error
- func RevokeToken() (bool, error)
- func SaveToken(token *StoredToken) error
- func SaveTokenForEndpoint(ep string, token *StoredToken) error
- func ServerSessionFromResponse(serverSessionID string) string
- type APIError
- type APIResponse
- type AuthClient
- func (c *AuthClient) AuthenticatedRequest(ctx context.Context, method, url string, data interface{}) (*APIResponse, error)
- func (c *AuthClient) Endpoint() string
- func (c *AuthClient) EnsureValidToken(bufferSeconds int) (*StoredToken, error)
- func (c *AuthClient) GetAuthFilePath() (string, error)
- func (c *AuthClient) GetToken() (*StoredToken, error)
- func (c *AuthClient) GetTokenForEndpoint(ep string) (*StoredToken, error)
- func (c *AuthClient) Handle401Error(token *StoredToken) (*StoredToken, error)
- func (c *AuthClient) IsAuthenticated() (bool, error)
- func (c *AuthClient) IsAuthenticatedForEndpoint(ep string) (bool, error)
- func (c *AuthClient) Login(ctx context.Context, deviceCode *DeviceCodeResponse, ...) error
- func (c *AuthClient) RemoveToken() error
- func (c *AuthClient) RemoveTokenForEndpoint(ep string) error
- func (c *AuthClient) RequestDeviceCode() (*DeviceCodeResponse, error)
- func (c *AuthClient) RevokeToken() (bool, error)
- func (c *AuthClient) SaveToken(token *StoredToken) error
- func (c *AuthClient) SaveTokenForEndpoint(ep string, token *StoredToken) error
- func (c *AuthClient) WithEndpoint(ep string) *AuthClient
- type AuthStore
- type AuthenticationError
- type DeviceAuthError
- type DeviceAuthPendingError
- type DeviceAuthSlowDownError
- type DeviceCodeRequest
- type DeviceCodeResponse
- type ErrorResponse
- type JWTExchangeResponse
- type LoginResult
- type StoredToken
- type TokenRefreshError
- type TokenRequest
- type TokenResponse
- type UserInfo
Constants ¶
const ( DeviceCodeEndpoint = "/api/auth/device/code" //nolint:gosec // not a credential DeviceTokenEndpoint = "/api/auth/device/token" //nolint:gosec // not a credential UserInfoEndpoint = "/oauth2/userinfo" )
Device Flow endpoints (RFC 8628)
const ( TokenEndpoint = "/oauth2/token" //nolint:gosec // not a credential RevokeEndpoint = "/oauth2/revoke" )
OAuth 2.0 endpoints
const ClientID = "ox"
ClientID is the OAuth client identifier for the ox CLI
Variables ¶
var DefaultScopes = []string{"user:profile", "sageox:write"}
DefaultScopes are the OAuth scopes requested during authentication
Functions ¶
func GetAuthFilePath ¶
GetAuthFilePath returns the path to the auth token file.
Path Resolution (via internal/paths package):
Default: ~/.sageox/config/auth.json With OX_XDG_ENABLE: $XDG_CONFIG_HOME/sageox/auth.json
See internal/paths/doc.go for architecture rationale.
func GetLoggedInEndpoints ¶
func GetLoggedInEndpoints() []string
GetLoggedInEndpoints returns all endpoints with valid (non-expired) tokens. Returns nil if no valid tokens exist.
func GetUserID ¶ added in v0.2.0
GetUserID returns the authenticated user's unique ID for the given endpoint. Returns empty string if not authenticated or on error.
func IsAuthRequired ¶
func IsAuthRequired() bool
IsAuthRequired checks if authentication is required based on the FEATURE_AUTH environment variable
func IsAuthenticated ¶
IsAuthenticated checks if a valid non-expired token exists for the current endpoint
func IsAuthenticatedForEndpoint ¶
IsAuthenticatedForEndpoint checks if a valid non-expired token exists for a specific endpoint
func IsCloudEnabled ¶
func IsCloudEnabled() bool
IsCloudEnabled checks if cloud features are enabled based on the FEATURE_CLOUD environment variable
func IsMemoryEnabled ¶ added in v0.3.0
func IsMemoryEnabled() bool
IsMemoryEnabled checks if memory features (ox memory, ox agent <id> distill) are enabled. Memory is experimental and not included in the default experience. Set FEATURE_MEMORY=true to enable.
func IsPostMVPEnabled ¶
func IsPostMVPEnabled() bool
IsPostMVPEnabled checks if post-MVP features (ox completion) are enabled. These features are for power users and not included in the MVP release. Set FEATURE_POST_MVP=true to enable.
func IsValidServerSessionID ¶
IsValidServerSessionID validates that the session ID has the correct format (starts with "oxsid_" and contains a valid ULID). Works for both client-generated and server-generated session IDs.
func ListEndpoints ¶
ListEndpoints returns all endpoints that have stored tokens
func Login ¶
func Login(ctx context.Context, deviceCode *DeviceCodeResponse, statusCallback func(string)) error
Login polls for the device authorization and completes the login process
func NewServerSessionID ¶
func NewServerSessionID() string
NewServerSessionID generates a new server session ID in the format: oxsid_<ulid>. This is used as fallback when server doesn't provide a session ID (offline mode).
func RemoveToken ¶
func RemoveToken() error
RemoveToken deletes the authentication token for the current API endpoint
func RemoveTokenForEndpoint ¶
RemoveTokenForEndpoint deletes the authentication token for a specific API endpoint
func RequireAuth ¶
func RequireAuth() error
RequireAuth checks if authentication is required and if the user is authenticated Returns an error if authentication is required but user is not authenticated
func RevokeToken ¶
RevokeToken revokes token and removes from local storage.
Best-effort server revocation:
- Prefers revoking refresh_token (more secure, invalidates both tokens)
- Falls back to access_token if refresh_token missing
- Always removes local token regardless of server response
Returns:
- true if server revocation succeeded (or no token to revoke)
- false if server revocation failed
- error if local token removal fails
Local token is always removed regardless of return value (unless removal itself fails).
func SaveToken ¶
func SaveToken(token *StoredToken) error
SaveToken saves the authentication token for the current API endpoint
func SaveTokenForEndpoint ¶
func SaveTokenForEndpoint(ep string, token *StoredToken) error
SaveTokenForEndpoint saves the authentication token for a specific API endpoint
func ServerSessionFromResponse ¶
ServerSessionFromResponse validates and returns a server-provided session ID. If the server ID is empty or invalid, generates a new client-side session ID as fallback for offline/degraded operation.
Design decision: Client fallback for offline Rationale: Graceful degradation - offline agents still get sessions; server-side preferred when available for security benefits.
Types ¶
type APIResponse ¶
type APIResponse struct {
StatusCode int
Data interface{} // parsed JSON or nil
Headers http.Header
}
APIResponse represents a response from an authenticated API request
func AuthenticatedRequest ¶
func AuthenticatedRequest(ctx context.Context, method, url string, data interface{}) (*APIResponse, error)
AuthenticatedRequest makes an authenticated HTTP request to the API.
Adds Bearer token to Authorization header. If request returns 401, attempts token refresh and retries once.
Args:
- ctx: Context for cancellation and timeout
- method: HTTP method (GET, POST, PUT, DELETE, etc.)
- url: Full URL to request
- data: Optional JSON body (will be serialized)
Returns:
- APIResponse with status, data, headers
Errors:
- AuthenticationError: If not logged in
- TokenRefreshError: If token refresh fails
- APIError: If API returns error after retry
type AuthClient ¶
type AuthClient struct {
// contains filtered or unexported fields
}
AuthClient provides authentication operations with configurable storage location. Use NewAuthClient() for production or NewAuthClientWithDir() for testing.
func NewAuthClient ¶
func NewAuthClient() *AuthClient
NewAuthClient creates an AuthClient using the default config directory and endpoint.
func NewAuthClientWithDir ¶
func NewAuthClientWithDir(configDir string) *AuthClient
NewAuthClientWithDir creates an AuthClient with a custom config directory. Primarily used for testing to isolate each test's auth storage.
func (*AuthClient) AuthenticatedRequest ¶
func (c *AuthClient) AuthenticatedRequest(ctx context.Context, method, url string, data interface{}) (*APIResponse, error)
AuthenticatedRequest makes an authenticated HTTP request using this client's token storage. This method enables test isolation by using the client's configDir for token storage.
func (*AuthClient) Endpoint ¶
func (c *AuthClient) Endpoint() string
Endpoint returns the configured API endpoint.
func (*AuthClient) EnsureValidToken ¶
func (c *AuthClient) EnsureValidToken(bufferSeconds int) (*StoredToken, error)
EnsureValidToken ensures we have a valid token, refreshing proactively if needed.
func (*AuthClient) GetAuthFilePath ¶
func (c *AuthClient) GetAuthFilePath() (string, error)
GetAuthFilePath returns the path to the auth token file for this client.
func (*AuthClient) GetToken ¶
func (c *AuthClient) GetToken() (*StoredToken, error)
GetToken loads the authentication token for this client's endpoint
func (*AuthClient) GetTokenForEndpoint ¶
func (c *AuthClient) GetTokenForEndpoint(ep string) (*StoredToken, error)
GetTokenForEndpoint loads the authentication token for a specific API endpoint
func (*AuthClient) Handle401Error ¶
func (c *AuthClient) Handle401Error(token *StoredToken) (*StoredToken, error)
Handle401Error handles 401 Unauthorized by attempting token refresh.
func (*AuthClient) IsAuthenticated ¶
func (c *AuthClient) IsAuthenticated() (bool, error)
IsAuthenticated checks if a valid non-expired token exists for this client's endpoint
func (*AuthClient) IsAuthenticatedForEndpoint ¶
func (c *AuthClient) IsAuthenticatedForEndpoint(ep string) (bool, error)
IsAuthenticatedForEndpoint checks if a valid non-expired token exists for a specific endpoint
func (*AuthClient) Login ¶
func (c *AuthClient) Login(ctx context.Context, deviceCode *DeviceCodeResponse, statusCallback func(string)) error
Login polls for the device authorization and completes the login process.
func (*AuthClient) RemoveToken ¶
func (c *AuthClient) RemoveToken() error
RemoveToken deletes the authentication token for this client's endpoint
func (*AuthClient) RemoveTokenForEndpoint ¶
func (c *AuthClient) RemoveTokenForEndpoint(ep string) error
RemoveTokenForEndpoint deletes the authentication token for a specific API endpoint
func (*AuthClient) RequestDeviceCode ¶
func (c *AuthClient) RequestDeviceCode() (*DeviceCodeResponse, error)
RequestDeviceCode initiates the device authorization flow.
func (*AuthClient) RevokeToken ¶
func (c *AuthClient) RevokeToken() (bool, error)
RevokeToken revokes token and removes from local storage for this client.
Best-effort server revocation:
- Prefers revoking refresh_token (more secure, invalidates both tokens)
- Falls back to access_token if refresh_token missing
- Always removes local token regardless of server response
Returns:
- true if server revocation succeeded (or no token to revoke)
- false if server revocation failed
- error if local token removal fails
Local token is always removed regardless of return value (unless removal itself fails).
func (*AuthClient) SaveToken ¶
func (c *AuthClient) SaveToken(token *StoredToken) error
SaveToken saves the authentication token for this client's endpoint
func (*AuthClient) SaveTokenForEndpoint ¶
func (c *AuthClient) SaveTokenForEndpoint(ep string, token *StoredToken) error
SaveTokenForEndpoint saves the authentication token for a specific API endpoint
func (*AuthClient) WithEndpoint ¶
func (c *AuthClient) WithEndpoint(ep string) *AuthClient
WithEndpoint returns a new AuthClient using the specified API endpoint. Trailing slashes are stripped to prevent double slashes in URL paths.
type AuthStore ¶
type AuthStore struct {
// Tokens maps API endpoint URLs to their authentication tokens
// e.g., "https://api.sageox.ai/" -> token, "https://sageox.walmart.com/" -> token
Tokens map[string]*StoredToken `json:"tokens"`
}
AuthStore holds tokens for multiple API endpoints
type AuthenticationError ¶
type AuthenticationError struct {
Message string
}
AuthenticationError is raised when authentication is required but user is not logged in
func (*AuthenticationError) Error ¶
func (e *AuthenticationError) Error() string
type DeviceAuthError ¶
type DeviceAuthError struct {
Message string
}
DeviceAuthError represents a device authorization failure
func (*DeviceAuthError) Error ¶
func (e *DeviceAuthError) Error() string
type DeviceAuthPendingError ¶
type DeviceAuthPendingError struct{}
DeviceAuthPendingError indicates the user hasn't authorized yet (not an error, used for control flow)
func (*DeviceAuthPendingError) Error ¶
func (e *DeviceAuthPendingError) Error() string
type DeviceAuthSlowDownError ¶
type DeviceAuthSlowDownError struct{}
DeviceAuthSlowDownError indicates the server requested slower polling
func (*DeviceAuthSlowDownError) Error ¶
func (e *DeviceAuthSlowDownError) Error() string
type DeviceCodeRequest ¶
DeviceCodeRequest represents the request body for device code endpoint
type DeviceCodeResponse ¶
type DeviceCodeResponse struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
VerificationURI string `json:"verification_uri"`
VerificationURIComplete string `json:"verification_uri_complete"`
ExpiresIn int `json:"expires_in"`
Interval int `json:"interval"`
}
DeviceCodeResponse represents the response from the device code endpoint
func RequestDeviceCode ¶
func RequestDeviceCode() (*DeviceCodeResponse, error)
RequestDeviceCode initiates the device authorization flow
type ErrorResponse ¶
type ErrorResponse struct {
Error string `json:"error"`
ErrorDescription string `json:"error_description"`
}
ErrorResponse represents an error response from the API
type JWTExchangeResponse ¶
type JWTExchangeResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
}
JWTExchangeResponse represents the response from JWT exchange endpoint
type LoginResult ¶
LoginResult contains the result of a login attempt
func LoginWithResult ¶
func LoginWithResult(timeout time.Duration, onStatus func(string)) *LoginResult
Login performs the full OAuth Device Authorization Flow with LoginResult return type This is a wrapper around the existing Login function that returns LoginResult instead of error for simpler handling in CLI code
type StoredToken ¶
type StoredToken struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresAt time.Time `json:"expires_at"`
TokenType string `json:"token_type"`
Scope string `json:"scope"`
UserInfo UserInfo `json:"user_info"`
}
StoredToken represents the authentication token stored locally
func EnsureValidToken ¶
func EnsureValidToken(bufferSeconds int) (*StoredToken, error)
EnsureValidToken ensures we have a valid token, refreshing proactively if needed.
Proactive refresh: If token expires within bufferSeconds (default 300 = 5 min), refresh it now to avoid expiration during a request.
Returns:
- Valid StoredToken, or nil if not authenticated
Raises:
- TokenRefreshError if refresh fails
func GetToken ¶
func GetToken() (*StoredToken, error)
GetToken loads the authentication token for the current API endpoint
func GetTokenForEndpoint ¶
func GetTokenForEndpoint(ep string) (*StoredToken, error)
GetTokenForEndpoint loads the authentication token for a specific API endpoint
func Handle401Error ¶
func Handle401Error(token *StoredToken) (*StoredToken, error)
Handle401Error handles 401 Unauthorized by attempting token refresh.
Reactive refresh: Called when a request returns 401, attempt refresh and return new token for retry.
Args:
- token: The current (possibly expired) token
Returns:
- New valid StoredToken after refresh
Raises:
- TokenRefreshError if refresh fails (user must re-authenticate)
func (*StoredToken) IsExpired ¶
func (t *StoredToken) IsExpired(bufferSeconds int) bool
IsExpired checks if the token is expired or will expire within the buffer seconds
type TokenRefreshError ¶
TokenRefreshError represents an error that occurred during token refresh
func (*TokenRefreshError) Error ¶
func (e *TokenRefreshError) Error() string
func (*TokenRefreshError) Unwrap ¶
func (e *TokenRefreshError) Unwrap() error
type TokenRequest ¶
type TokenRequest struct {
GrantType string `json:"grant_type"`
DeviceCode string `json:"device_code"`
ClientID string `json:"client_id"`
}
TokenRequest represents the request body for device token endpoint