Documentation
¶
Overview ¶
Package auth provides credential persistence and renewal for the BuildMax client. It depends on internal/config for the file location and internal/interface/client to exchange a refresh token, and on nothing from the TUI, desktop, or Cobra layers above it.
Index ¶
- Variables
- func ArtifactPublisherForSession() tool.ArtifactPublisher
- func CanAuthenticate(serverURL string) error
- func Clear(path string) error
- func IsLoggedIn() (bool, error)
- func Logout() error
- func LogoutAndRevoke() error
- func RequireLogin() error
- func Save(creds *Credentials, path string) error
- func SaveCredentials(creds *Credentials) error
- func TokenForServer(serverURL string) (string, error)
- type AuthInfo
- type Credentials
- type ModelSource
Constants ¶
This section is empty.
Variables ¶
var ErrLoginExpired = errors.New("login has expired")
ErrLoginExpired means a login is stored but no longer works: its refresh token expired, or the session was revoked.
It is distinct from a deployment that cannot be reached, because the answer is different. An unreachable server may come back; an expired login will not, and the session cannot continue until someone signs in again or returns to local mode. Neither is a reason to quietly use local models: that would send a prompt somewhere the user did not choose. See docs/design/client-modes.md section 8.
Functions ¶
func ArtifactPublisherForSession ¶
func ArtifactPublisherForSession() tool.ArtifactPublisher
ArtifactPublisherForSession returns this session's artifact capability, or nil when it has none.
Being logged in is the whole precondition, and it is answered here at assembly time rather than discovered when the model calls the tool. A session with no server keeps its ordinary local output behaviour, and its agent is never offered a tool that could only fail — see docs/design/unified-artifacts.md section 7.1.
func CanAuthenticate ¶
CanAuthenticate reports whether a call to serverURL could authenticate, without making one.
TokenForServer answers the same question by renewing when it has to, which contacts the server and rotates the stored refresh token. That is the wrong thing for a diagnostic to do: `buildmax doctor` is read-only, and a check that quietly spends a credential is not a check.
func Clear ¶
Clear removes the credentials file at path. It is not an error if the file does not exist.
func IsLoggedIn ¶
IsLoggedIn reports whether valid credentials are present.
func LogoutAndRevoke ¶
func LogoutAndRevoke() error
LogoutAndRevoke clears the stored credentials and asks the server to revoke the session behind them.
The local file is cleared whether or not the server can be reached. Someone who typed `buildmax logout` on a machine with no network is signed out of that machine; leaving the credentials behind because a call failed would be the opposite of what they asked for. The returned error reports what could not be revoked, and is worth printing but not worth failing on.
func RequireLogin ¶
func RequireLogin() error
RequireLogin returns an error when no valid credentials are present.
func Save ¶
func Save(creds *Credentials, path string) error
Save marshals creds to JSON and writes them to path, creating parent directories as needed.
The write goes to a temporary file and is renamed into place. Refreshing rewrites this file while other BuildMax processes may be reading it, and a truncate-then-write would let one of them load a half-written file and conclude it is not signed in.
func SaveCredentials ¶
func SaveCredentials(creds *Credentials) error
SaveCredentials persists a login result.
func TokenForServer ¶
TokenForServer returns a usable access token for calls to serverURL, renewing it first if it is spent or nearly so.
It refuses to hand the credential to any other host. A managed model entry names its own server, and settings.yaml is editable by anything running as the user, so a mismatch would otherwise send a BuildMax token — and every prompt that follows — wherever that file said.
Types ¶
type AuthInfo ¶
type AuthInfo struct {
LoggedIn bool `json:"logged_in"`
ServerURL string `json:"server_url,omitempty"`
UserID string `json:"user_id,omitempty"`
Email string `json:"email,omitempty"`
Name string `json:"name,omitempty"`
}
AuthInfo is the caller-facing authentication view.
type Credentials ¶
type Credentials struct {
ServerURL string `json:"server_url"`
// Token is the access token. The field keeps its original name so that a
// credentials file written before refresh tokens existed still loads.
Token string `json:"token"`
// RefreshToken renews the access token without another login code. Empty
// means this login ends when Token expires — either an old file or a server
// that stores no refresh tokens.
RefreshToken string `json:"refresh_token,omitempty"`
UserID string `json:"user_id"`
Email string `json:"email"`
Name string `json:"name"`
SavedAt time.Time `json:"saved_at"`
}
Credentials holds the persisted authentication state (server URL, both halves of the login, and basic user info). Stored as JSON on disk.
func Load ¶
func Load(path string) (*Credentials, error)
Load reads credentials from path. If the file does not exist, it returns (nil, nil) — not an error. Any other read or parse failure is an error.
func StoredLogin ¶
func StoredLogin() (*Credentials, error)
StoredLogin returns the credentials on disk whether or not they still work, and nil when there are none.
This is the mode, and it is deliberately not Info(): Info answers "am I signed in" and reports a spent login as signed out, which would make an expired session look like local mode. See ResolveModelSource.
func (*Credentials) IsUsable ¶
func (c *Credentials) IsUsable() bool
IsUsable reports whether these credentials can still authenticate a call, either because the access token is good or because it can be renewed.
This is the question every command actually has: "am I signed in?" — not "is this particular token still fresh?", which stopped being the same question once a refresh token existed.
func (*Credentials) IsValid ¶
func (c *Credentials) IsValid() bool
IsValid returns true when the credentials contain a non-empty, unexpired access token. It parses the exp claim from the token payload without verifying the signature (clients don't have the server secret).
type ModelSource ¶
type ModelSource struct {
// ServerURL is the deployment serving these models, empty in local mode.
ServerURL string
// Entries is what that deployment offers. Nil in local mode, where the
// caller uses settings.yaml instead.
Entries []config.ModelEntry
// Default is the model name a new session starts with, as the deployment
// marked it. Empty in local mode, where settings.yaml says.
Default string
}
ModelSource is where a surface's models come from.
A login is the mode: with one the models are the deployment's and every prompt goes there, without one they are the ones in settings.yaml and each call is made from this machine. The two are never mixed — see docs/design/client-modes.md section 1.
func ResolveModelSource ¶
func ResolveModelSource(ctx context.Context) (ModelSource, error)
ResolveModelSource asks the deployment this machine is signed in to what it offers, or reports local mode when there is no login.
Managed mode fetches eagerly rather than on first use. The list carries each model's context window, which the session needs before it can compact, and a deployment that cannot be reached must fail where the user is still deciding what to do rather than mid-turn. There is no fallback to local models: that would send a prompt somewhere the user did not choose.
func (ModelSource) Managed ¶
func (s ModelSource) Managed() bool
Managed reports whether these models are served by a deployment.