Sign in with ChatGPT

Vish Srinivasan

Your user already pays OpenAI twenty dollars a month. Your app charges them again to call the same models. That's a billing bug, not a business model.

chatgpt-oauth is my fix — an experimental "Sign in with ChatGPT" for your own software, riding the same public OAuth client the Codex CLI uses. The user signs in with their ChatGPT account, the app runs on their subscription, and no API key ever changes hands.

One protocol, four implementations

The repo ships TypeScript, Swift, Python, and Kotlin. The hard part wasn't any one of them — it was keeping four of them honest. All four implement a single written contract, PROTOCOL.md: the wire protocol, the refresh lifecycle, the threat model. House rule: a behavior difference between ports is a bug, not a dialect.

Writing the contract first changed everything downstream. There's one spec and four translations, each with tests asserting the same lifecycle — instead of four codebases slowly inventing their own opinions.

Three decisions carry the weight

  • Subject-keyed custody. There is no store.load() — only store.load(subject), where the subject comes from your app's own authenticated session. The claims inside ChatGPT's JWT are unverified: fine for display, never for identity.
  • Singleflight refresh. Five concurrent requests hit an expired token; one refresh happens, four adopt the winner via compare-and-swap. A refresh stampede is how you get a user's session revoked.
  • Quarantine, not deletion. invalid_grant marks the subject needs-reauth. A 429 or 5xx never destroys credentials. Transient failure and terminal failure get different funerals.

The honest part

All of this rides an undocumented backend, which is why the README's warning block is longer than its pitch. Treat refresh tokens like passwords. Never pool or resell subscription access. Keep an API-key fallback. Building on unofficial ground is fine — pretending the ground is official is not.