diff --git a/CHANGELOG.md b/CHANGELOG.md index c9a99a3..ac93034 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,62 @@ All notable changes to Armature are documented here. +## v0.6.9 — Session Lifetime Config + +Admin-configurable session durations, "keep me logged in" opt-in, and +optional idle timeout. Completes the auth hardening started in v0.6.8. + +### Added + +- **Admin session settings**: `session.access_token_ttl` (default 15m, + clamp 5m–60m) and `session.refresh_token_ttl` (default 7d, clamp + 1h–90d) stored in `global_settings`. New `LoadSessionConfig()` helper + reads and clamps values with `parseDurationString()` supporting `m`, + `h`, `d` suffixes. +- **"Keep me logged in" checkbox**: Login form opt-in. Checked = full + `refresh_token_ttl`. Unchecked = capped at 24h. Cookie `max-age` + tracks whichever lifetime was chosen. `keep_login` flag stored on + refresh token row. +- **Config-driven token generation**: `generateTokens()` reads TTLs from + `global_settings` instead of hardcoded `15*time.Minute` / + `7*24*time.Hour`. Response includes `expires_in` and + `refresh_expires_in` (seconds) so the client schedules refresh + correctly. +- **Idle timeout (optional)**: Admin-toggleable (default off). Server + checks `last_activity_at` on refresh-token row; rejects if gap exceeds + `session.idle_timeout`. Client SDK pings `POST /api/v1/auth/activity` + on click/keydown (debounced, max 1/min). +- **Admin Settings > Session section**: Dropdowns for access TTL, refresh + TTL, and idle timeout with toggle. +- **7 new tests**: Duration parsing, clamping (low/high), defaults, + invalid values, empty idle timeout. + +### Changed + +- `CreateRefreshToken` store method now accepts `keepLogin bool` + parameter; both Postgres and SQLite implementations updated. +- `GetRefreshTokenInfo` returns `RefreshTokenInfo` struct with + `UserID`, `KeepLogin`, `LastActivityAt` for idle-timeout decisions. +- SDK `auth.login()` accepts optional third `keepLogin` parameter; + cookie max-age derived from server `refresh_expires_in` response. +- SDK boots activity tracking after successful auth boot. + +## v0.6.8 — Cookie Fix + UI Hardening Roadmap + +### Fixed + +- **Session cookie max-age bug**: `arm_token` cookie was set to 15 min + (matching access token) while refresh token lasted 7 days. Cookie now + matches refresh token lifetime so Go SSR middleware can serve page + shells while JS refreshes the access token client-side. + +### Added + +- **ROADMAP-UI.md**: Detailed UI hardening roadmap (v0.6.9–v0.6.15) + covering session config, viewport foundation, CSS deduplication, + extension CSS isolation, responsive layout, visual polish, and + automated usability survey gate. + ## v0.6.7 — Native mTLS End-to-end mutual TLS without a reverse proxy. Targets systemd+podman diff --git a/ROADMAP-UI.md b/ROADMAP-UI.md index 8d4374d..038e89c 100644 --- a/ROADMAP-UI.md +++ b/ROADMAP-UI.md @@ -40,20 +40,10 @@ ## Roadmap -### v0.6.9 — Session Lifetime Config +### v0.6.9 — Session Lifetime Config ✅ -Make session duration admin-configurable and expose "keep me logged in" in the -login UI. The cookie max-age bug is already fixed (v0.6.8 shipped with 15-min -cookie vs 7-day refresh token; now both are 7 days, and the Go SSR middleware -accepts expired-but-signed JWTs so JS can refresh client-side). - -| Step | Description | -|------|-------------| -| Admin session settings | Add `session.access_token_ttl` (default `15m`) and `session.refresh_token_ttl` (default `7d`) to the admin settings surface. Stored in the `settings` table, read by `generateTokens()`. Both values clamp to a sane range (access: 5m–60m, refresh: 1h–90d). | -| "Keep me logged in" checkbox | Login form gets an opt-in checkbox. When checked, the refresh token gets the full `refresh_token_ttl`. When unchecked, refresh token lifetime = `24h` (session-length). The cookie max-age tracks whichever lifetime was chosen. | -| Token generation uses config | `handlers/auth.go generateTokens()` reads TTLs from config instead of hardcoded `15 * time.Minute` / `7 * 24 * time.Hour`. The `expires_in` field in the JSON response reflects the actual access TTL so the client schedules refresh correctly. | -| Idle timeout (optional) | If the admin enables idle timeout (default: off), the server checks `last_activity_at` on the refresh-token row. If the gap exceeds `session.idle_timeout` (e.g. `2h`), the refresh is rejected. The client SDK pings `/api/v1/auth/activity` on user interaction (debounced, max once per minute). | -| Validation | Test matrix: default config, short access (5m), long refresh (30d), keep-me-logged-in on/off, idle timeout on/off. Background tab for >access TTL then navigate — should not redirect to login. | +Shipped. Admin-configurable TTLs, "keep me logged in" checkbox, idle timeout, +config-driven `generateTokens()`, 7 new tests. See CHANGELOG.md for details. ### v0.6.10 — Viewport Foundation @@ -132,7 +122,7 @@ Make the UI machine-auditable so Claude Code can run an automated survey. ## Sequencing Rationale ``` -v0.6.9 Session Lifetime Config ← Cookie bug fix already shipped; make TTLs configurable +v0.6.9 Session Lifetime Config ✅ SHIPPED ↓ v0.6.10 Viewport Foundation ← Everything depends on correct containment ↓ diff --git a/VERSION b/VERSION index fae59ca..1a5ac0d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.8 +0.6.9