Skip to content

feature/api key authentication#28

Merged
nahime0 merged 18 commits intomainfrom
feature/api-key-authentication
May 5, 2026
Merged

feature/api key authentication#28
nahime0 merged 18 commits intomainfrom
feature/api-key-authentication

Conversation

@nahime0
Copy link
Copy Markdown
Member

@nahime0 nahime0 commented May 5, 2026

  • Add apiauth package for Bearer token derivation and middleware
  • Protect API endpoints with Bearer-token authentication
  • Add passphrase subcommand to set or rotate the API passphrase
  • Document passphrase-based API authentication
  • Track empty internal/assets/dist for go:embed
  • Tighten config file permissions to 0o600
  • Scrub passphrase from Wails GetConfig binding
  • Allow Authorization header in CORS preflight
  • Standardize stdout/stderr for passphrase subcommand
  • Warn when env var would override a passphrase rotation
  • Test ResolvePassphrase priority ladder
  • Warn about short passphrase before asking for confirmation
  • Warn loudly when API server starts without authentication
  • Flag env/config divergence in passphrase --show
  • Document subtle invariants in apiauth and playground
  • Harden API passphrase authentication
  • Document hardened API authentication
  • Remove unreachable search extractor code

nahime0 added 18 commits May 5, 2026 15:39
The bearer token is derived from a passphrase stored in the config file.
On --api startup, prompt for one if missing, save it, derive the token,
and print it to stderr. The playground HTML page stays public; all data
endpoints require Authorization: Bearer or ?token= for SSE clients. The
passphrase is stripped from /api/config responses.
`lazyagent passphrase` always prompts (double-entry confirmation),
saves the new passphrase to the config, and prints the derived bearer
token. `--show` is read-only and prints the token for the configured
passphrase or LAZYAGENT_API_PASSPHRASE without writing.
http-api.md gains an Authentication section with the PBKDF2 algorithm
parameters, a pinned test vector, and reference snippets in JS, Swift,
Kotlin, and shell. Recipes, CLI reference, configuration, quickstart,
architecture, and roadmap are updated to reflect the new behavior and
the passphrase subcommand.
The //go:embed all:dist directive in internal/assets/assets.go fails
with 'no matching files found' on a fresh clone because frontend/dist/
hasn't been built yet. Keep an empty .gitkeep so go build works without
running 'make build' first; ignore everything else placed inside
internal/assets/dist/ (the Makefile copies the real bundle in).
The config file now carries the API passphrase, so anyone who can read
it can derive the bearer token. Create with 0o600, chmod existing files
on every save so old 0o644 configs get tightened on first upgrade-write,
and tighten the parent directory to 0o700.
SessionService.GetConfig() is exposed to the Svelte frontend via Wails
IPC. The HTTP /api/config handler already zeroes the field; mirror that
here so the secret never crosses the IPC boundary either. Otherwise any
script the Webview loads (or DevTools) can read the passphrase and
derive the bearer token.
Cross-origin clients (a future web companion app served from a different
origin, or the playground when --host is on a non-default address) need
to send Authorization: Bearer. Without listing it in the preflight
allow-list browsers reject the request.
`lazyagent passphrase --show` now writes only the raw bearer token to
stdout so it can be captured in a pipe (TOKEN=$(lazyagent passphrase
--show)). Everything else, including the rotation flow, keeps all
output on stderr — same convention as the --api setup banner — so a
piped invocation cannot accidentally land a token in someone else's
pipe.
If LAZYAGENT_API_PASSPHRASE is set, the next `--api` start uses it
regardless of what's saved in the config. Without a warning, a user
running `lazyagent passphrase` to rotate would see the new bearer
token printed but the next server start would still accept the old
one — confusing footgun.
Cover env-var precedence, configured-value fallback, whitespace
handling on both sources, and the ErrNoTTY path when no source is
available. The interactive TTY branch is left to manual testing.
Previously the warning landed AFTER the user had already typed the
passphrase twice; aborting meant rerunning the command. Surface the
warning between the two prompts so Ctrl+C is a usable escape.
Empty bearerToken disables auth as a deliberate test/opt-out hook. Log
a clear warning so an accidentally-empty value (e.g. via a typo'd env
var pipeline) is surfaced instead of silently running an open server.
When both LAZYAGENT_API_PASSPHRASE and the config file are set but
hold different values, the env var wins at --api start. Print a note
so a user who just rotated and forgot to unset the env var sees the
mismatch instead of being puzzled by a stale token.
ConstantTimeCompare leaks length on mismatch — call out why that's
fine here (fixed 43-char tokens, length is public). Note in the
playground that the bearerToken global is XSS-safe today only because
no third-party scripts are loaded; flag it for future maintainers.
@nahime0 nahime0 merged commit 3419705 into main May 5, 2026
@nahime0 nahime0 deleted the feature/api-key-authentication branch May 5, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant