HoffDesk Auth Unification
Date: 2026-04-24
Decision by: Matt (Director)
Affects: All /admin/* routes, dashboard, API consumers, webhooks
The Decision
Two auth patterns, no exceptions:
| Consumer | Auth Method | How |
|---|---|---|
| Browser (human) | Session cookie | Login page → server sets sessionid cookie → validated on every request |
| API / Webhook / Bot | Bearer token | X-Hoffdesk-Secret or Authorization: Bearer <token> header |
No query-param tokens. No meta-tag secrets. No mixed patterns.
Migration Map
| Current Pattern | Route | Migrate To |
|---|---|---|
X-Admin-Token header |
/admin/blog/* |
Session cookie (browser) or Bearer token (API) |
?token=hoffdesk-admin-2025 query param |
/admin/content/generate* |
Session cookie (browser) or Bearer token (API) |
X-Hoffdesk-Secret header |
/family/events/removed |
Bearer token (it's a machine-to-machine call) |
| Session login (no route) | /admin/family/login |
Session cookie (wire the route, this was already the plan) |
| Telegram secret | /telegram/callback |
Keep as-is (internal bot webhook) |
| Webhook secret | /webhook |
Keep as-is (internal service webhook) |
Implementation Plan
Socrates (Backend)
-
Add session middleware to hoffdesk-api
- Login endpoint:POST /auth/login— validates credentials, setssessionidcookie
- Logout endpoint:POST /auth/logout— clears cookie
- Session middleware: checkssessionidcookie on all/admin/*routes
- Token middleware: checksAuthorization: Bearer <token>orX-Hoffdesk-Secretheader on/api/*routes -
Unify admin auth
-/admin/blog/*→ require session cookie OR Bearer token
-/admin/family/*→ require session cookie OR Bearer token
-/admin/content/*→ require session cookie OR Bearer token
- Kill?token=query param pattern -
Keep webhook/bot auth as-is
-/telegram/callback→ internal secret validation (unchanged)
-/webhook→ internal validation (unchanged)
-/family/events/removed→ Bearer token (machine-to-machine)
Daedalus (Frontend)
-
Blog admin — replace
X-Admin-TokenHTMX interceptor with session cookie flow
- Add login page redirect when 401 received
- Remove?token=from all content generation URLs
- HTMX handles cookies automatically (same-origin) -
Family dashboard — use proxy pattern for removed-events
- Dev server proxies/family/events/removedand injects auth header
- No client-side secrets in production -
Login page —
/admin/blog/loginand/admin/family/loginshare one template, one flow
Credentials
- Admin session: Matt logs in with username/password →
sessionidcookie (httpOnly, Secure, SameSite=Strict) - API tokens: One
Hoffdesk-Secretfor internal services (webhooks, dashboard proxy), oneadmin-tokenfor API consumers - Aundrea's access: She logs in once → session cookie → never sees a token
What This Unblocks
- Aundrea can access the family dashboard without seeing API secrets
- All admin routes use the same login flow
- API consumers (scripts, bots) use tokens
- No more auth surprise when switching between blog admin and family admin