Documentation
¶
Overview ¶
Package auth resolves the active environment (base-URL + API key) and stores API keys in the OS keychain. The NORMATIK_API_KEY env var has strict precedence over the keychain so CI/headless/agent use never needs a keychain.
Index ¶
- Constants
- Variables
- func DeleteKey(profile string) error
- func DeleteKeyIfPresent(profile string) error
- func Detect(ctx context.Context, site, apiKey string, hc *http.Client) (string, error)
- func GetKey(profile string) (string, error)
- func PollBrowserLogin(ctx context.Context, start *BrowserLoginStart, hc *http.Client) (string, error)
- func SetKey(profile, key string) error
- type BrowserLoginStart
- type Resolved
Constants ¶
const Service = "normatik-cli"
Service is the keychain service name under which keys are stored, keyed by profile name.
Variables ¶
var ErrBrowserLoginUnsupported = errors.New("server does not support browser login (no /cli-auth endpoints)")
ErrBrowserLoginUnsupported signals a backend without the /cli-auth endpoints (404/405 on start): an older server that only supports the paste path.
var ErrKeyAlreadyDelivered = errors.New("approval succeeded but the key was already delivered (410)")
ErrKeyAlreadyDelivered signals a 410 on poll whose body carries errorCode CLI_AUTH_KEY_ALREADY_DELIVERED: the flow WAS approved and its key was already handed out once. This is the transport-drop case: a later explicit poll receives this 410, so a usable key exists server-side and cannot be re-fetched. Terminal: caller must warn about a dangling key rather than report a plain expiry.
var ErrKeyDeliveredUnreadable = errors.New("approval succeeded but the key response could not be read (200)")
ErrKeyDeliveredUnreadable signals a 200 on poll whose body could not be decoded into a usable key (truncated/corrupt response, or missing apiKey). The backend consumes the nonce and wipes the raw key in the SAME transaction as the 200, so the key is already minted-and-spent: retrying only yields a 410. This is terminal, NOT transient — the caller must warn that a dangling key exists server-side rather than silently retry into an "expired" message.
var ErrNonceInvalid = errors.New("approval expired, denied or already used (410)")
ErrNonceInvalid signals a 410 on poll for a user-code that is unknown, expired, or was never approved (denied). The backend reports errorCode CLI_AUTH_NONCE_INVALID for these; no server-side key exists.
var ErrRateLimited = errors.New("rate limited (429)")
ErrRateLimited signals a 429 on start or poll.
Functions ¶
func DeleteKeyIfPresent ¶
DeleteKeyIfPresent removes the stored API key for a profile; an absent key is not an error (used by `auth remove`, where the profile may never have had a key or was already logged out).
func Detect ¶
Detect probes <site>/api/public/v1/users/me and returns the canonical site URL when the key authenticates. Every Normatik environment uses the /api prefix.
func PollBrowserLogin ¶
func PollBrowserLogin(ctx context.Context, start *BrowserLoginStart, hc *http.Client) (string, error)
PollBrowserLogin POSTs the public user-code and private verifier to the base that start resolved. Returns ("", nil) while pending (202), the API key exactly once when approved (200) and ErrRateLimited on 429. A 410 maps by its errorCode: CLI_AUTH_KEY_ALREADY_DELIVERED -> ErrKeyAlreadyDelivered (a dangling key exists), anything else (or an absent/unparseable body) -> ErrNonceInvalid.
Types ¶
type BrowserLoginStart ¶
type BrowserLoginStart struct {
BaseURL string
UserCode string
BrowserURL string
IntervalSeconds int
// contains filtered or unexported fields
}
BrowserLoginStart is the decoded /cli-auth/start response plus the canonical site URL used by start and poll.
func StartBrowserLogin ¶
func StartBrowserLogin(ctx context.Context, site, keyNameSuggestion string, readOnly bool, hc *http.Client) (*BrowserLoginStart, error)
StartBrowserLogin POSTs to the fixed /api/cli-auth/start endpoint.
type Resolved ¶
type Resolved struct {
BaseURL string
APIKey string
Profile string // resolved profile name ("" = none / env-only)
}
Resolved is the outcome of credential resolution.
func Resolve ¶
Resolve determines the base-URL and API key.
Site-URL precedence: --profile flag's profile URL > NORMATIK_BASE_URL env > active-profile URL. There is NO implicit localhost fallback: when nothing is configured BaseURL stays "" and callers must surface a clean CONFIG error (client commands) or prompt for it (login) — the CLI never silently talks to localhost. API-key precedence: NORMATIK_API_KEY env (strict, for CI/headless) > keychain for the resolved profile.