-
Notifications
You must be signed in to change notification settings - Fork 0
ADR 0002 session cookie auth
Status: Accepted
MyACE originally had no real authentication — every request carried a
hardcoded nil UUID that the backend silently mapped to one shared
placeholder account. Closing that gap meant picking a real session
mechanism for the web UI. Two mainstream options existed: a signed session
cookie (server-side session state, or a stateless signed cookie), or a
JWT issued at login and stored in the browser (typically localStorage),
sent as a Bearer header on every request.
The frontend already had unused, half-wired scaffolding for the JWT/
localStorage approach — api.ts's request() helper read a
myace_token key from localStorage and attached it as Bearer, but
nothing ever populated that key. The scaffolding suggested that was the
original intended direction.
Use a cookie-based session (Starlette SessionMiddleware, signed with
APP_SECRET_KEY) for the web UI, and keep the CLI's separate Bearer-token
mechanism (ApiToken, bcrypt-hashed, unrelated to the session) exactly as
it was. get_current_user accepts either.
-
Finish the JWT/localStorage scaffolding — rejected. Both dev (Vite
proxy) and prod (nginx) already serve
/api/*on the same origin as the frontend, which is exactly the condition under which cookie-based sessions work cleanly with zero CORS complication — the cross-origin problem JWT/localStorage is usually reached for to solve doesn't exist here. A token sitting inlocalStorageis also readable by any script on the page, which is a real XSS blast-radius difference against anHttpOnlycookie, for no offsetting benefit in this deployment shape. -
One unified mechanism for both the web UI and the CLI — rejected. The
CLI has no browser, no cookie jar, and already had a working, tested
Bearer-token flow (
myace login --token) predating this change. Forcing it onto cookies would have meant a strictly worse CLI UX for no gain;get_current_usersupporting both mechanisms costs a few lines and lets each client use what actually fits it.
- The half-built
myace_token/localStoragescaffolding inapi.tswas removed as dead code once the cookie session replaced it. -
SessionMiddlewareis now load-bearing for two things at once: it backs the actual user session, and Authlib's OIDC login flow needs it to storestate/nonce during the redirect handshake. Removing it breaks both — see debugging.md. -
APP_SECRET_KEYwent from a cosmetic default to something that actually matters: it signs every session cookie. The app now warns at startup if the placeholder value is still in use outside development — see SECURITY.md. - Every frontend
fetch()call must setcredentials: 'same-origin'or the cookie silently isn't sent. This bit two hand-rolledfetch()calls inImportPage.tsxthat bypassed the sharedapi.tshelper.
The warning described above was later hardened: the app now refuses to
start (RuntimeError in app/main.py) if APP_SECRET_KEY is still the
default placeholder and app_env != "development", rather than just
logging a warning. See SECURITY.md.
Generated from docs/ by scripts/sync_wiki.py. Back to repo
- Home
- Architecture
- Data Model
- Invariants
- Extending MyACE
- Debugging
-
ADR Index
- ADR-0001-canonical-ir-as-markdown-with-frontmatter
- ADR-0002-session-cookie-auth
- ADR-0003-ownership-based-authorization
- ADR-0004-github-export-via-rest-api
- ADR-0005-email-password-baseline-auth
- ADR-0006-encrypted-admin-editable-secrets
- ADR-0007-additive-user-role-column
- ADR-0008-collection-moderation-state-machine
- ADR-0009-manifest-based-drift-detection
- ADR-0010-structured-handoff-field
- ADR-0011-public-demo-sandbox
- ADR-0012-manual-collection-freshness-verification
- ADR-0013-post-hoc-unpublish
- Adapter Research