auth

package
v0.0.4 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 16 Imported by: 0

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

View Source
const Service = "normatik-cli"

Service is the keychain service name under which keys are stored, keyed by profile name.

Variables

View Source
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.

View Source
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.

View Source
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.

View Source
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.

View Source
var ErrRateLimited = errors.New("rate limited (429)")

ErrRateLimited signals a 429 on start or poll.

Functions

func DeleteKey

func DeleteKey(profile string) error

DeleteKey removes the stored API key for a profile.

func DeleteKeyIfPresent

func DeleteKeyIfPresent(profile string) error

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

func Detect(ctx context.Context, site, apiKey string, hc *http.Client) (string, error)

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 GetKey

func GetKey(profile string) (string, error)

GetKey reads the API key for a profile from the OS keychain.

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.

func SetKey

func SetKey(profile, key string) error

SetKey stores the API key for a profile in the OS keychain.

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

func Resolve(cfg *config.Config, profileFlag string) (Resolved, error)

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.

Jump to

Keyboard shortcuts

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