Walking skeleton — magic link to signed cookie, proven live
Increment 1 ships the same day as the scaffold: a Phoenix app with the full identity schema, an Ed25519 keypair behind a JWKS endpoint, and the whole magic-link → didi_session cookie → /api/me → refresh → logout loop — 19 tests green and every step proven against the live server by a curl script.
Why Care?
The identity service stopped being a spec today. The core loop every didi.sh service will depend on — prove who you are once, carry a locally-verifiable signed cookie everywhere — runs end to end on localhost, with the exact token discipline the spec pinned: EdDSA-signed (consumers can verify, never mint), short-lived tokens over a rolling server-side session, single-use hashed magic-link tokens, invite-only posture (unknown emails get a silent 202 — no account enumeration).
What's Here
The full identity schema in one migration — users (didi_id UUIDv7, hand-rolled generator), organizations (domain-as-id), firm_profiles, memberships, oauth_accounts, login_tokens (unified magic-link/invite table), sessions, auth_events, apps. The skeleton wires four of them; the rest are data-shape ready for increments 3–4.
Keys + tokens — Ed25519 via JOSE; dev keypair auto-generated (gitignored), prod key injected as
ID_SIGNING_JWK; public half served at/.well-known/jwks.jsonwith the RFC 7638 thumbprint as kid.The API — POST /api/magic-links (202 always), /api/magic-links/redeem (single-use, atomic claim), /api/session/refresh (accepts an expired-but-authentic token; the session row is the refresh authority), DELETE /api/session, GET /api/me.
Proof —
scripts/prove-skeleton.shwalks issue → redeem → reuse- rejected → me → JWKS → refresh → logout → post-logout-rejected against the live server. Plus 19 ExUnit tests including expiry, tamper, and case-insensitive email matching.
Gotcha Worth Logging
Appending config to the END of config.exs puts it after
import_config "#{config_env()}.exs" — silently overriding every per-env
file. Five tests failed with a misleading "no signing key" error before the
block moved above the import. Config order is load-bearing in Phoenix apps.
What's Next
Increment 2: augment-it's TS verify adapter (cookie parse on the workspace WS upgrade + JWKS verify), replacing the flat token map — then invites and the LiveView admin (increment 3), which makes reach-edu + humain-vc onboarding real.
