Documentation
¶
Overview ¶
Package remote implements the client-side wiring for targeting a klaus-gateway instead of a locally-running klaus container.
The Target type composes the request URL, the routing headers (X-Klaus-Channel, X-Klaus-Channel-ID, X-Klaus-User-ID, X-Klaus-Thread-ID), and the bearer token used by `klausctl run`, `klausctl prompt`, and `klausctl messages` when `--remote=URL` is set.
Index ¶
Constants ¶
const ( // ChannelHeader identifies where a gateway request originated. ChannelHeader = "X-Klaus-Channel" // ChannelIDHeader scopes the channel to a specific identity (hostname). ChannelIDHeader = "X-Klaus-Channel-ID" // UserIDHeader carries the authenticated user identity. UserIDHeader = "X-Klaus-User-ID" // ThreadIDHeader carries the conversation/session identity. ThreadIDHeader = "X-Klaus-Thread-ID" // ChannelCLI is the value sent on ChannelHeader for klausctl CLI calls. ChannelCLI = "cli" )
Variables ¶
This section is empty.
Functions ¶
func DefaultSession ¶
func DefaultSession() string
DefaultSession returns the stable default thread id derived from the current working directory. Same directory -> same thread id across invocations, so a user running `klausctl prompt --remote=...` twice from the same repo reuses the same conversation thread.
func NormalizeBaseURL ¶
NormalizeBaseURL validates a remote URL and strips any trailing slash and any `/v1` suffix so path composition stays predictable.
func ResolveChannelID ¶
func ResolveChannelID() string
ResolveChannelID returns the host identity used in X-Klaus-Channel-ID. Falls back to "unknown" when the hostname cannot be resolved.
func ResolveUserID ¶
ResolveUserID extracts the user identity used in X-Klaus-User-ID. It prefers the `sub` claim from the bearer token JWT (if the token parses cleanly), falling back to $USER, then the current uid, then "unknown".
Types ¶
type AuthRecord ¶
type AuthRecord struct {
// ServerURL is the remote klaus-gateway root (normalized).
ServerURL string `yaml:"server_url"`
// Issuer is the OAuth authorization server issuer URL (from discovery).
Issuer string `yaml:"issuer"`
// AccessToken is the current access token.
AccessToken string `yaml:"access_token"`
// TokenType is the token type, typically "Bearer".
TokenType string `yaml:"token_type,omitempty"`
// RefreshToken is used to mint a new access token without re-login.
RefreshToken string `yaml:"refresh_token,omitempty"`
// ExpiresAt is the absolute expiry time of AccessToken.
ExpiresAt time.Time `yaml:"expires_at,omitempty"`
// Scope is the scope granted for the access token, if reported.
Scope string `yaml:"scope,omitempty"`
// TokenEndpoint is the OAuth token endpoint (cached so refresh can
// proceed without repeating discovery).
TokenEndpoint string `yaml:"token_endpoint,omitempty"`
// ClientID is the OAuth client identifier used during the original
// authorization (typically the CIMD URL).
ClientID string `yaml:"client_id,omitempty"`
}
AuthRecord is the per-host credential record persisted on disk.
ExpiresAt is the absolute expiry of AccessToken. When the access token is about to expire, callers should refresh using RefreshToken.
func Login ¶
func Login(ctx context.Context, store *AuthStore, serverURL string, opts LoginOptions) (*AuthRecord, error)
Login performs browser-based OAuth login against a remote klaus-gateway and persists the resulting credentials in the given AuthStore. It reuses the pkg/oauth helpers for discovery/PKCE/callback and implements the authorization-URL build + token exchange locally so the resulting AuthRecord captures the token endpoint and client id needed for later refresh-on-401 in pkg/remote/refresh.go.
func Refresh ¶
func Refresh(ctx context.Context, httpClient *http.Client, rec AuthRecord) (AuthRecord, error)
Refresh exchanges the refresh token stored in rec for a new access token via the cached token endpoint. The updated record (same fields, new AccessToken/ExpiresAt/RefreshToken) is returned; callers are responsible for persisting it with AuthStore.Put.
If the server rejects the refresh (401/invalid_grant) Refresh returns *ErrReloginRequired so the caller can surface a "re-run auth login" hint to the user.
type AuthStore ¶
type AuthStore struct {
// contains filtered or unexported fields
}
AuthStore manages host-keyed OAuth records at ~/.config/klausctl/auth/. Files are written with 0600 and the parent directory with 0700.
func NewAuthStore ¶
NewAuthStore returns an AuthStore backed by the given directory.
func (*AuthStore) Delete ¶
Delete removes the record for the given server URL. Missing files are treated as success.
func (*AuthStore) Get ¶
func (s *AuthStore) Get(serverURL string) (*AuthRecord, error)
Get returns the stored record for the given server URL, or nil when none exists. Only read errors other than ENOENT surface as errors.
func (*AuthStore) List ¶
func (s *AuthStore) List() ([]AuthRecord, error)
List returns all stored records sorted by server URL.
func (*AuthStore) Put ¶
func (s *AuthStore) Put(rec AuthRecord) error
Put writes a record for the given server URL with file mode 0600.
type ErrReloginRequired ¶
ErrReloginRequired is returned when the stored refresh token is missing or the OAuth server rejects it. Callers surface this to the user as a prompt to re-run `klausctl auth login --remote=...`.
func (*ErrReloginRequired) Error ¶
func (e *ErrReloginRequired) Error() string
type LoginOptions ¶
type LoginOptions struct {
// ClientID is the OAuth client identifier; defaults to the public
// CIMD URL (oauth.DefaultClientIDMetadataURL).
ClientID string
// Scopes is the space-separated scope string to request. Defaults
// to "openid profile email groups offline_access".
Scopes string
// HTTPClient is used for the token exchange; defaults to
// http.DefaultClient when nil.
HTTPClient *http.Client
// BrowserOpener opens the authorize URL in the user's browser.
// Defaults to oauth.OpenBrowser.
BrowserOpener func(string) error
}
LoginOptions controls Login behaviour. Fields left at zero fall back to sensible defaults (CIMD URL, default scopes, http.DefaultClient).
type Target ¶
type Target struct {
// BaseURL is the gateway root, for example "https://gw.example.com".
BaseURL string
// Instance is the klaus instance name — becomes the `{instance}` path
// segment in completions/MCP URLs.
Instance string
// BearerToken is attached as `Authorization: Bearer <token>` when set.
BearerToken string
// ChannelID (hostname) identifies the caller's machine.
ChannelID string
// UserID identifies the authenticated user (JWT `sub` or $USER).
UserID string
// ThreadID identifies the conversation/session (defaults to a stable
// hash of the working directory when the user does not set --session).
ThreadID string
}
Target describes a remote klaus-gateway endpoint plus the routing identities attached to every request.
func NewTarget ¶
NewTarget composes a Target from a remote URL, instance name, session override (may be empty) and bearer token (may be empty). Channel ID and user ID are resolved from the host environment.
func (Target) CompletionsURL ¶
CompletionsURL is the OpenAI-compatible chat-completions endpoint for this target: `<base>/v1/<instance>/chat/completions`.