From 22e90adab70428eda4575e7b293d7f8344380222 Mon Sep 17 00:00:00 2001 From: Utkarsh Sengar Date: Wed, 27 May 2026 13:35:45 -0700 Subject: [PATCH] docs: note auth.md decision (right shape, wait for adoption) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Captures the reasoning behind not migrating to WorkOS's auth.md agent-verified flow yet. The spec is the right shape — (iss, sub) is stable per-human across sessions, same role github_user_id plays today — but no major agent runtime has shipped issuer-side ID-JAG issuance, so there'd be nothing to verify against. Trip-wire TODO points future-us at the migration when an issuer ships. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 19 +++++++++++++++++++ src/github-oauth.ts | 8 ++++++++ 2 files changed, 27 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index cce44d8..fc2bf38 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -170,6 +170,25 @@ new account can be created with `github_user_id = NULL`. The UNIQUE index uses a partial-index `WHERE github_user_id IS NOT NULL` so the legacy rows don't collide. +**auth.md (not yet, May 2026):** considered WorkOS's `auth.md` +agent-verified flow as a replacement for the human checkpoint at +`/verify`. The spec is the right shape — every attestation is an +ID-JAG (audience-scoped JWT) signed by the agent provider with `iss` ++ `sub` claims, where `sub` is *"an opaque user identifier"* stable +per-human across sessions. That's the same role `github_user_id` +plays today: one human running N agent sessions resolves to one +`(iss, sub)` pair, not N accounts. **Decision: don't migrate yet.** +Adoption is the blocker — no major agent runtime (Anthropic / +OpenAI / Cursor / Replit Agent) has shipped issuer-side ID-JAG +issuance as of 2026-05-27. Without an issuer there's nothing to +verify, so a `/auth.md` + `/agent/auth` endpoint would advertise a +flow no agent can complete. When at least one runtime ships +issuer-side, the migration is small: keep `users`, add `(iss, sub)` +columns alongside `github_user_id`, accept either as identity, keep +GitHub OAuth as fallback for non-attesting agents. The TODO marker +in `src/github-oauth.ts` is the trip-wire. Track: Anthropic +changelog for "ID-JAG" / "agent attestation" / "auth.md." + **Token storage convention (agent-side):** 1. `./.htmlbin/token` — project-local, preferred (no permission prompt for agents that won't write outside cwd) diff --git a/src/github-oauth.ts b/src/github-oauth.ts index c3aa372..3d6a08d 100644 --- a/src/github-oauth.ts +++ b/src/github-oauth.ts @@ -9,6 +9,14 @@ // real friction (rate limits, email verification, the slow ramp on a // throwaway account's reputation) which is the point. // +// TODO(auth.md): when at least one major agent runtime (Anthropic, +// OpenAI, Cursor, …) actually ships ID-JAG issuance with a public +// JWKS, add a second registration path that swaps github_user_id for +// the (iss, sub) pair from the attestation. Keep GitHub OAuth as a +// fallback for agents whose provider doesn't attest. Spec is fine +// (sub is stable per-human, same shape as github_user_id), adoption +// is what we're waiting on. See CLAUDE.md "auth.md (not yet)". +// // Flow: // 1. Human lands on /verify?code= // 2. Clicks "Sign in with GitHub" → GET /auth/github/start?code=