Your users sign in with their own ChatGPT account and run prompts on it. You never pay OpenAI — they use their own plan.
Quick start · Two runners · Headless · Deploy · Security
A headless React component that adds a "Login with ChatGPT" button to your app.
Click it, your user approves on auth.openai.com, and you can run prompts on their
ChatGPT plan. The OAuth flow, the popup, the polling, the sessions — all handled.
OAuth tokens never touch the browser. They live on a backend you control; the
browser only ever sees an HttpOnly cookie and the streamed output.
Not published to npm — on purpose (see the disclaimer). Use it from a clone via
npm link.
# 1. clone and build this repo
git clone https://github.com/AsyncFuncAI/CodexAuth
cd CodexAuth && npm install && npm run build && npm link
# 2. in YOUR app, link it
cd /path/to/your-app
npm link codex-authNow import { CodexAuth } from "codex-auth" resolves to your local clone.
(Prefer a lockfile entry? Use "codex-auth": "file:../CodexAuth" in your app's
package.json instead of npm link.)
1. Frontend — drop in the component:
import { CodexAuth } from "codex-auth";
<CodexAuth onAuthenticated={({ account }) => console.log("hi", account)} />2. Backend — mount one route (Express shown; Next.js below):
import { createCodexRouter } from "codex-auth/backend";
import { directRunner } from "codex-auth/backend/direct";
app.use("/api/codex", createCodexRouter({
runner: directRunner(),
cookieSecret: process.env.COOKIE_SECRET!,
}));That's it. The component talks to /api/codex/* on the same origin by default.
One-time, per user: they enable device code authorization in ChatGPT → Settings → Security & Login. The component shows this hint automatically when needed.
The component is always the same. The runner decides how your backend reaches OpenAI:
| Runner | How | Deploys on |
|---|---|---|
directRunner |
Pure fetch to OpenAI. No binary. |
Anywhere — incl. Vercel serverless / edge |
defaultCliRunner |
Shells out to the codex CLI. |
A persistent Node host (Railway, Docker, VPS) |
Both implement the same interface and keep tokens server-side. directRunner is
the recommended default — frontend + backend can live in one Vercel/Next.js deploy.
| Import | For |
|---|---|
codex-auth/backend |
Express — createCodexRouter |
codex-auth/backend/next |
Next.js App Router route handler |
codex-auth/backend/direct |
the serverless-friendly directRunner |
codex-auth/backend/worker |
Cloudflare Worker proxy |
Next.js — one file, zero config
// app/api/codex/[...codex]/route.ts
import { createNextCodexHandler } from "codex-auth/backend/next";
import { directRunner } from "codex-auth/backend/direct";
export const { GET, POST } = createNextCodexHandler({
runner: directRunner(),
cookieSecret: process.env.COOKIE_SECRET!,
});Pass a function as children for full control — no default UI is rendered:
<CodexAuth>
{(auth) =>
auth.isAuthenticated
? <button onClick={auth.logout}>Sign out {auth.account}</button>
: <button onClick={auth.login}>Login with ChatGPT</button>
}
</CodexAuth>Run a prompt against the user's account once authenticated:
auth.run("Write a haiku about the ocean.", {
onText: (text) => append(text),
onDone: ({ text }) => console.log(text),
});Prefer a hook? useCodexAuth() returns the same auth object.
Browser <CodexAuth/> Your backend OpenAI
│ click login │ │
├── open popup (sync) ─────────┤ │
├── POST /session ────────────▶│ │
├── POST /login/start ────────▶│── device code ───────▶ │
│ show code, poll status │◀── loginUrl + code ────│
│ user approves in popup ───────────────────────────▶ │
├── GET /status (poll) ───────▶│◀── tokens (stay here) ─│
│ authenticated ✓ │ │
├── POST /run/stream ─────────▶│── run prompt ────────▶ │
│ stream output ◀─────────────│◀── tokens never leave ─│
The popup is opened synchronously on click (so the blocker allows it), then
redirected to the validated auth.openai.com URL once the backend returns it.
Full HTTP spec in CONTRACT.md.
git clone https://github.com/AsyncFuncAI/CodexAuth
cd CodexAuth && npm install
cp demo/.env.example demo/.env # set COOKIE_SECRET
npm run demo # app → :5173, backend → :8787CodexClientConfig (component / hook options)
| Option | Default | Purpose |
|---|---|---|
basePath |
/api/codex |
Base path for the contract |
pollIntervalMs |
3000 |
Status poll cadence |
resumeMaxAgeMs |
86_400_000 |
Resume a persisted session within 24h |
storage |
localStorage |
Persistence; null disables (SSR-safe) |
credentials |
same-origin |
fetch credentials mode |
allowedLoginHosts |
["auth.openai.com"] |
Hosts the login popup may open |
enableGravatar |
false |
Opt-in Gravatar avatar |
useCodexAuth() returns: status, account, userCode, loginUrl, error,
popupBlocked, isAuthenticated / isConnecting / isWaiting, avatarUrl, and
the actions login(), logout(), cancelLogin(), run(), copyUserCode().
Cross-origin backends
When the app and backend are on different origins, set credentials: 'include'
on the client and pass allowedOrigins: ['https://your-app.example'] to the
router (it emits credentialed CORS for that specific origin, never *).
This project is for education and research. You alone are responsible for how you use it.
<CodexAuth> reuses OpenAI's first-party Codex CLI OAuth client and talks to
undocumented Codex endpoints off-label. This very likely violates OpenAI's Terms
of Use. OpenAI's ChatGPT plans explicitly prohibit, among other things:
- Abusive usage, such as automatically or programmatically extracting data.
- Sharing your account credentials or making your account available to anyone else.
- Reselling access or using ChatGPT to power third-party services.
Using this to power an app for other users falls squarely under that last point.
By using this software, you acknowledge that:
- You are solely responsible for ensuring your use complies with OpenAI's Terms of Use and Usage Policies.
- It may get your account, your users' accounts, or the shared OAuth client rate-limited, suspended, or banned, at OpenAI's discretion.
- The undocumented endpoints can change or break at any time with no notice.
- The authors provide this as-is, with no warranty, and accept no liability for any consequence of its use (see the MIT License).
Do not build a product or business on this. For anything real, use the
official OpenAI API with your own key, or have each
user bring their own key. See SECURITY.md for the full trust model.
MIT · Not affiliated with or endorsed by OpenAI · For research & education only

