yingjieli-admin-auth v1.0.0
subsystem yingjieli.site
capsule://quake0day/yingjieli-admin-auth@1.0.0
Single source of truth for "is this request the site admin?". Implements a
password login that yields an HMAC-signed session cookie (7-day TTL),
plus per-IP brute-force rate limiting via Cloudflare KV.
Owns
- POST /api/auth (login), DELETE /api/auth (logout), GET /api/auth (status)
- the yl_admin HttpOnly cookie format and TTL
- HMAC session token construction and verification
- per-IP rate limit (5 attempts / 5 min) backed by KV
- the isAuthed(request, env) helper that every other capsule must use
Does not own
- the admin's *identity* beyond "knows the shared password" (single-user system)
- what an authed admin is allowed to do (other capsules enforce their own write gates)
- user-facing login UI (lives in yingjieli-admin-ui)
AI orientation
This capsule is the only thing that says "request is admin". Other
capsules MUST import isAuthed() from site/functions/_lib/auth.js — they
must never decode the cookie themselves and must never re-implement
HMAC verification. The session format is `admin.<exp>.<sig_b64url>`;
if you change it, also bump the cookie name (yl_admin) so old cookies
invalidate cleanly.
Avoid
- Decoding the yl_admin cookie outside this capsule.
- Storing the password or hash anywhere in code or KV (env var only).
- Removing the Secure / HttpOnly / SameSite=Strict cookie flags.
- Skipping the constant-time compare branch in /api/auth POST.
Extension points
rate-limit-policyatsite/functions/_lib/auth.js:checkPasswordRateLimit- Pure (env, ip) -> { ok, retryAfter? }. Safe to tighten the
threshold (currently 5 / 5min). Do not move state out of KV.
Provides
http_api:auth-login— POST /api/auth — exchange password for session cookie.http_api:auth-logout— DELETE /api/auth — clear session cookie.http_api:auth-status— GET /api/auth → { authenticated: bool }.library:auth-helpers— isAuthed, createSession, verifySession, setSessionCookie, clearSessionCookie, json, unauthorized, checkPasswordRateLimit.
Requires
env:ADMIN_PASSWORD— Shared admin password. REQUIRED; POST /api/auth 500s without it.env:SESSION_SECRET— HMAC signing key for session tokens. Falls back to ADMIN_PASSWORD if unset (NOT recommended).env:YL_DATA— KV namespace; used for per-IP rate-limit counters (rl:auth:<ip>).
Dependencies
Runtime
node>=18cloudflare-pages*
Invariants (must always hold)
- A revoked / expired session must never authenticate a subsequent request.
- ADMIN_PASSWORD must never appear in any response body or log line.
- Cookie is always Secure + HttpOnly + SameSite=Strict.
- Rate-limit window cannot be bypassed by removing the rl:auth:<ip> key from the client side.
Glossary
session- HMAC-signed token in the yl_admin cookie, scope `admin`, 7-day TTL
rate-limit- per-IP attempt counter at KV key `rl:auth:<ip>`
isAuthed- the single function every other capsule calls to gate writes