Run AI agents using Claude Max or ChatGPT Plus/Pro subscription credits — no paid API keys needed.
auth-agent stores OAuth credentials for Anthropic and OpenAI Codex on your local machine and exposes them as:
- A CLI — log in, check status, and run one-off prompts
- A Node.js library — call Claude or GPT-4o from any TypeScript/JavaScript project by reading the saved credentials
- Prerequisites
- Installation
- Quick Start
- CLI Reference
- Library Usage
- Configuration
- Development
- Contributing
- License
| Requirement | Version |
|---|---|
| Node.js | ≥ 20.0.0 |
| npm | ≥ 10 |
Claude Code CLI (claude) |
Latest — for Anthropic login |
| ChatGPT Plus or Pro account | — for OpenAI Codex login |
npm install -g auth-agentnpm install auth-agent# Step 1 — Generate a setup token with the Claude Code CLI
claude setup-token
# Step 2 — Save it to auth-agent
auth-agent auth login --provider anthropic
# Paste the sk-ant-oat-... token when prompted
# Step 3 — Run a prompt
auth-agent run "Explain PKCE in one sentence" --provider anthropic# Step 1 — Authenticate via browser (PKCE OAuth flow)
auth-agent auth login --provider openai-codex
# A browser window opens; sign in with your ChatGPT account
# Step 2 — Run a prompt
auth-agent run "What is 2 + 2?" --provider openai-codexAuthenticate with a provider and save credentials locally.
auth-agent auth login --provider <provider>
| Provider | Auth method | Credential type |
|---|---|---|
anthropic |
Paste sk-ant-oat-... token from claude setup-token |
Static bearer token |
openai-codex |
Browser-based PKCE OAuth flow | Refreshable OAuth token |
Anthropic example:
# First generate the token:
claude setup-token
# Then paste it here:
auth-agent auth login --provider anthropicOpenAI Codex example (local machine):
auth-agent auth login --provider openai-codex
# A browser window opens automaticallyOpenAI Codex example (headless / SSH server):
auth-agent auth login --provider openai-codex
# Prints a URL — paste it in your local browser, then paste the redirect URL backDisplay all saved credentials and their validity.
auth-agent auth statusExample output:
Store: /Users/you/.auth-agent/auth-profiles.json
anthropic:subscription: ✓ valid (token, expiry: no expiry)
openai-codex:subscription: ✓ valid
expires: 3/10/2026, 7:15:00 AM
accountId: user_abc123
Delete stored credentials for a provider.
auth-agent auth remove --provider <provider>auth-agent auth remove --provider anthropic
auth-agent auth remove --provider openai-codexRun a single prompt using stored credentials.
auth-agent run <prompt> --provider <provider> [--model <model>] [--max-tokens <n>]
| Flag | Default | Description |
|---|---|---|
--provider |
(required) | anthropic or openai-codex |
--model |
claude-sonnet-4-5 / gpt-4o |
Model ID to use |
--max-tokens |
1024 |
Maximum tokens to generate |
Examples:
# Claude (default model: claude-sonnet-4-5)
auth-agent run "Write a haiku about TypeScript" --provider anthropic
# Claude with specific model
auth-agent run "Write a haiku" --provider anthropic --model claude-opus-4-5
# GPT-4o (default model: gpt-4o)
auth-agent run "What is PKCE?" --provider openai-codex
# GPT-4o mini with token limit
auth-agent run "Hello" --provider openai-codex --model gpt-4o-mini --max-tokens 256auth-agent exports a TypeScript-first library for use inside other projects. The user must have previously run auth-agent auth login on their machine.
npm install auth-agentReturns a valid access token for the given provider. Handles OAuth token refresh automatically — your code never needs to deal with expiry.
import { resolveToken } from "auth-agent";
const { token, provider } = await resolveToken("anthropic");
// token: "sk-ant-oat-..."
const { token: codexToken } = await resolveToken("openai-codex");
// token: "eyJhbGci..." (JWT, auto-refreshed if expired)Signature:
resolveToken(provider: "anthropic" | "openai-codex"): Promise<ResolvedToken>
type ResolvedToken = {
token: string;
accountId?: string; // present for openai-codex
provider: string;
};Throws if no credentials are found (user has not logged in) or if a static token has expired.
Call Claude with a subscription token. Returns the full response text and token usage.
import { resolveToken, callAnthropic } from "auth-agent";
const { token } = await resolveToken("anthropic");
const response = await callAnthropic({
token,
model: "claude-sonnet-4-5",
prompt: "Explain dependency injection in one paragraph.",
maxTokens: 512,
});
console.log(response.text);
console.log(`Tokens: ${response.usage.inputTokens} in / ${response.usage.outputTokens} out`);Options:
type AnthropicCallOptions = {
token: string; // from resolveToken("anthropic")
model: string; // e.g. "claude-sonnet-4-5", "claude-opus-4-5"
prompt: string;
maxTokens?: number; // default: 1024
};
type AnthropicCallResult = {
text: string;
model: string;
usage: { inputTokens: number; outputTokens: number };
};Call GPT-4o (or other OpenAI models) with a ChatGPT Plus/Pro subscription token. The API uses SSE streaming internally; callCodex returns the accumulated text once complete.
The accountId is extracted automatically from the JWT — do not pass it manually.
import { resolveToken, callCodex } from "auth-agent";
const { token } = await resolveToken("openai-codex");
const response = await callCodex({
token,
model: "gpt-4o",
prompt: "What is the capital of France?",
maxTokens: 256,
});
console.log(response.text);Options:
type CodexCallOptions = {
token: string; // from resolveToken("openai-codex")
model: string; // e.g. "gpt-4o", "gpt-4o-mini"
prompt: string;
maxTokens?: number; // default: 1024
};
type CodexCallResult = {
text: string;
model: string;
};import { resolveToken, callAnthropic, callCodex } from "auth-agent";
async function runWithProvider(provider: "anthropic" | "openai-codex", prompt: string) {
const { token } = await resolveToken(provider);
if (provider === "anthropic") {
const { text } = await callAnthropic({ token, model: "claude-sonnet-4-5", prompt });
return text;
} else {
const { text } = await callCodex({ token, model: "gpt-4o", prompt });
return text;
}
}
const answer = await runWithProvider("anthropic", "Hello!");For advanced use cases (e.g. building your own provider or inspecting stored credentials):
import { loadStore, getProfile } from "auth-agent";
const store = loadStore();
const cred = getProfile(store, "anthropic:subscription");
if (cred?.type === "token") {
console.log("Anthropic token:", cred.token);
}Exported types:
import type {
AuthProfileStore, // { version: 1; profiles: Record<string, AuthProfileCredential> }
AuthProfileCredential, // TokenCredential | OAuthCredential
TokenCredential, // { type: "token"; provider: string; token: string; expires?: number }
OAuthCredential, // { type: "oauth"; provider: string; access: string; refresh: string; expires: number }
} from "auth-agent";Credentials are stored as JSON on your local filesystem. No secrets are sent to any server.
Resolution order (first match wins):
| Priority | Condition | Path |
|---|---|---|
| 1 | AUTH_AGENT_STORE_DIR is set |
$AUTH_AGENT_STORE_DIR/auth-profiles.json |
| 2 | XDG_CONFIG_HOME is set |
$XDG_CONFIG_HOME/auth-agent/auth-profiles.json |
| 3 | Default | ~/.auth-agent/auth-profiles.json |
The file is created with 600 permissions (owner read/write only).
| Variable | Required | Description |
|---|---|---|
AUTH_AGENT_STORE_DIR |
No | Override the credential store directory (useful for CI or multi-user setups) |
XDG_CONFIG_HOME |
No | XDG Base Directory — respected if set |
CI / isolated environment example:
export AUTH_AGENT_STORE_DIR=/tmp/my-ci-store
auth-agent auth statusgit clone https://github.com/you/auth-agent.git
cd auth-agent
npm install| Command | Description |
|---|---|
npm run build |
Compile TypeScript to dist/ |
npm run dev |
Run CLI directly from source (no build step) via tsx |
npm test |
Run full test suite (Vitest, single-run) |
npm run test:watch |
Run tests in watch mode |
npm run prepublishOnly |
Build + test (runs automatically before npm publish) |
npm run dev -- auth status
npm run dev -- auth login --provider anthropic
npm run dev -- run "Hello!" --provider anthropicnpm test # all tests
npm test test/codex-call.test.ts # single file
npm run test:watch # watch modeAll tests use Vitest. The test suite mocks fetch via vi.stubGlobal and uses temporary directories for credential store isolation — no real network calls are made.
npm run build
# Output: dist/ (JS + .d.ts type declarations + source maps)src/
cli.ts Entry point — Commander.js command definitions
config.ts Credential store path resolution
index.ts Public library exports
auth/
types.ts Credential type definitions
store.ts Read/write auth-profiles.json
anthropic.ts Anthropic login flow (paste setup-token)
codex.ts OpenAI Codex login flow (PKCE OAuth)
resolve.ts Token resolution + OAuth auto-refresh
llm/
anthropic-call.ts Claude API call using @anthropic-ai/sdk
codex-call.ts GPT-4o call via ChatGPT Codex endpoint (SSE)
test/
store.test.ts Store read/write unit tests
resolve.test.ts Token resolution + refresh unit tests
codex-call.test.ts Codex headers, body, SSE parsing tests
See CONTRIBUTING.md.