Skip to main content

Local Python access to OAuth-authenticated Codex and Claude Code agents

Project description

PyPI - Version PyPI - Python Version PyPI - License PyPI - Downloads PyPI Downloads GitHub Actions Documentation Status

🚧 Under Development

This project is still in an alpha stage. Expect rapid changes, incomplete features, and possible breaking updates between releases.

  • The API may evolve as we stabilize core functionality.
  • Documentation and examples are incomplete.
  • Feedback and bug reports are especially valuable at this stage.

oauthpy

Local Python access to OAuth-authenticated coding agents.

oauthpy is a local, user-operated Python library that wraps local Codex and Claude Code sessions behind a small, typed, async-core-with-sync-facade API:

  • Codex (OpenAI), driven by the official codex CLI via codex exec --json
  • Claude Code (Anthropic), driven by the official claude-agent-sdk

It is not a hosted service, a multi-user gateway, or a credential broker. It runs on your machine and lets you either isolate provider login state under ~/.oauthpy/ or explicitly reuse the normal vendor CLI/session state.

Scope

In scope for v0.1:

  • One-shot execution via Client.run(prompt, cwd=..., model=..., timeout=..., env=..., provider_options=...).
  • Streaming via Client.stream(...) as an async iterator of normalized Event records.
  • Best-effort, read-only Client.auth_status() per provider.
  • Client.login() that shells out to the provider's official login flow.
  • Client.available() installed/provider-ready check.
  • Auth-source selection: auto, oauthpy, or external.
  • A tiny debugging CLI (oauthpy run, oauthpy interactive, oauthpy auth login, oauthpy auth status, oauthpy available).

Out of scope for v0.1:

  • Hosting, relaying, or proxying anyone else's OAuth.
  • Reverse-engineering vendor web endpoints.
  • Scraping TUI output.
  • Wire-compatibility with vendor cloud APIs.
  • Persistent multi-turn session management. oauthpy interactive is only a local in-memory debugging facade.
  • Editing ~/.codex/auth.json or Claude credential files directly.

Installation

python -m pip install oauthpy

Python 3.10+. Cross-platform (Windows, Linux, macOS).

Auth prerequisites

oauthpy never implements vendor OAuth itself in v0.1. It delegates login, refresh, and credential formats to the provider's official local tooling.

  • Default isolated login: oauthpy auth login --provider codex or oauthpy auth login --provider claude. This creates ~/.oauthpy/<provider>/ with private directory permissions where supported, then runs the official CLI login with provider-specific config env vars.
  • External session reuse: existing codex and claude logins are still reusable out of the box. The default auth_source="auto" prefers authenticated oauthpy-isolated state, then falls back to normal vendor CLI/session state.
  • Forced source: use Client("codex", auth_source="oauthpy") for isolated state or Client("claude", auth_source="external") for normal vendor behavior.

Provider-specific auth isolation:

  • Codex — install the codex CLI (npm i -g @openai/codex). In oauthpy source mode, oauthpy sets CODEX_HOME=~/.oauthpy/codex and ensures config.toml contains cli_auth_credentials_store = "file" unless you already set a supported value (file, keyring, or auto).
  • Claude — install the Claude Code CLI. The Python claude-agent-sdk dependency is installed with oauthpy by default. In oauthpy source mode, oauthpy sets CLAUDE_CONFIG_DIR=~/.oauthpy/claude for CLI status/login and SDK runs.

Normal Claude login uses claude auth login. claude setup-token is a separate headless/CI helper that prints a long-lived token; oauthpy does not use it for regular login.

See docs/auth.md for details.

Codex quickstart

from oauthpy import Client

client = Client("codex")
result = client.run("Summarize this repo", cwd=".")
print(result.text)

Streaming:

import asyncio
from oauthpy import Client

async def main():
    async for event in Client("codex").stream("Refactor module X", cwd="."):
        print(event.kind, event.text)

asyncio.run(main())

Claude quickstart

from oauthpy import Client

client = Client("claude")
result = client.run("Write a failing test first for foo()", cwd=".")
print(result.text)

Streaming is identical: async for event in Client("claude").stream(prompt, cwd="."): ....

Model and reasoning defaults

oauthpy applies lightweight per-run defaults without editing your vendor config files:

  • Codex uses the Codex CLI's provider/default model, but sends model_reasoning_effort=low through --config unless you override it.
  • Claude Code uses the documented opus model alias and low effort by default through ClaudeAgentOptions(model="opus", effort="low").

Override the model with the shared model= argument:

Client("codex").run("summarize", cwd=".", model="gpt-5.3-codex")
Client("claude").run("summarize", cwd=".", model="sonnet")

Override reasoning effort through provider options:

Client("codex").run("deep review", provider_options={"reasoning_effort": "high"})
Client("claude").run("deep review", provider_options={"reasoning_effort": "high"})

CLI equivalents:

oauthpy run --provider codex --reasoning-effort high "review this repo"
oauthpy run --provider claude --model sonnet --reasoning-effort low "summarize this repo"

Interactive helpers mirror the upstream naming:

  • Codex reasoning efforts: minimal, low, medium, high, xhigh.
  • Claude effort levels: low, medium, high, xhigh, max.
  • Claude model aliases include default, best, sonnet, opus, haiku, sonnet[1m], opus[1m], and opusplan.

Inside oauthpy interactive, use /model NAME, /model clear, /effort LEVEL, /effort clear, /models, and /efforts.

Auth-source selection

Client(provider, auth_source="auto", oauthpy_home=None) keeps the shared API small while making auth state explicit:

Source Behavior
auto Prefer authenticated ~/.oauthpy/<provider>/ state; otherwise reuse normal vendor CLI/session auth; if login is needed, create isolated oauthpy state.
oauthpy Force isolated state under OAUTHPY_HOME or ~/.oauthpy.
external Force normal vendor behavior without oauthpy env overrides.

CLI equivalents:

oauthpy auth login --provider codex          # defaults to --source oauthpy
oauthpy auth login --provider claude --source external
oauthpy auth status --provider codex --source auto
oauthpy run --provider claude --source oauthpy "summarize this repo"
oauthpy interactive --provider codex --source auto --cwd .

Interactive CLI

Use oauthpy interactive to debug setup and try repeated prompts without writing Python:

oauthpy interactive --provider codex --source auto --cwd .
oauthpy interactive --provider claude --source auto --cwd .

Plain text sends a transcript-aware chat turn. Slash commands handle setup and diagnostics: /status, /available, /login, /provider, /source, /cwd, /model, /models, /effort, /reasoning, /efforts, /timeout, /events, /run, /stream, /clear, /help, and /exit.

Slash-command tab completion is enabled when prompt-toolkit is installed. It is part of oauthpy's default install; if it is unavailable, the CLI falls back to standard input() without completion.

Example Claude session:

$ oauthpy interactive --provider claude --source auto --cwd .
oauthpy interactive. Type /help for commands; /exit to quit.
oauthpy[claude:auto]> Hello, is claude code ready?
claude> Yes, Claude Code is ready! How can I help you today?
oauthpy[claude:auto]>

In this example, --source auto does not ask oauthpy to implement OAuth itself. It asks oauthpy to resolve local auth state: first use authenticated isolated Claude Code config under ~/.oauthpy/claude if present, otherwise fall back to the normal Claude Code CLI/session auth on the machine. oauthpy passes the resolved non-secret environment/config location to the official Claude Code CLI/SDK and never prints token values.

oauthpy chat remains as a compatibility alias for the same local in-memory interaction mode.

CLI setup debugging walk-through

Use this sequence when validating a fresh machine or debugging provider setup. It checks the Python package, the vendor CLIs, auth-source resolution, one-shot runs, and the examples separately so failures are easier to localize.

Create a clean environment and install oauthpy:

conda create -y -n oauthpy python=3.12 pip
conda activate oauthpy
python -m pip install -e ".[dev]"
python -c "from oauthpy import Client; print(Client)"
oauthpy --help

Check that the provider CLIs are installed and visible:

codex --version
claude --version

Inspect auth without printing secrets:

oauthpy auth status --provider codex --source auto --json
oauthpy auth status --provider claude --source auto --json
oauthpy available --provider codex
oauthpy available --provider claude
oauthpy interactive --provider codex --source auto --cwd .

If either provider is unauthenticated, use oauthpy-isolated login by default:

oauthpy auth login --provider codex
oauthpy auth login --provider claude

To debug against the normal vendor CLI/session state instead, force external mode:

oauthpy auth status --provider codex --source external --json
oauthpy auth status --provider claude --source external --json

Run minimal one-shot smoke tests:

oauthpy run --provider codex --source auto --cwd . "Reply with exactly oauthpy-codex-smoke"
oauthpy run --provider claude --source auto --cwd . "Reply with exactly oauthpy-claude-smoke"

Then run the examples:

python examples/basic_codex.py
python examples/basic_claude.py
python examples/stream_codex.py
python examples/stream_claude.py

Failure triage:

  • If Conda cannot create the environment, check network access to the configured channels and use writable cache directories such as CONDA_PKGS_DIRS=/tmp/oauthpy-conda-pkgs and XDG_CACHE_HOME=/tmp/oauthpy-cache.
  • If auth succeeds but Codex runs fail with a read-only filesystem error, ensure Codex can write its session/config state, or run an oauthpy-isolated login with a writable OAUTHPY_HOME.
  • If Claude auth succeeds but runs hang, test the upstream CLI directly with claude -p "Reply with exactly oauthpy-claude-smoke" to separate Claude Code/network issues from oauthpy wrapper issues.
  • Do not copy, paste, commit, or share credential files from ~/.oauthpy/ or the normal vendor config directories.

Architecture note

Codex and Claude Code expose very different integration surfaces on the supported, local path:

  • Codex does not have a stable Python SDK in v0.1, but its official CLI already has a mature codex exec --json mode that emits a JSONL event stream. oauthpy parses that stream into normalized Event records.
  • Claude Code ships an official Python SDK (claude-agent-sdk) with a streaming query(prompt, options=ClaudeAgentOptions(...)) entrypoint. oauthpy calls that directly instead of shelling out.

Both adapters normalize to the same Event / RunResult / AuthStatus models and preserve the raw provider payload on Event.raw so advanced callers can drop down a level when they need to.

Security note

oauthpy is designed to run on your machine, for your account. It:

  • never prints or persists OAuth tokens beyond what the upstream tool already does;
  • creates ~/.oauthpy/ and provider subdirectories with 0700 permissions where the OS supports it;
  • never copies existing vendor tokens into ~/.oauthpy/ by default;
  • never edits normal vendor credential files directly;
  • passes subprocess arguments as argv lists (shell=False everywhere);
  • redacts secrets from logs, reprs, and exception messages on a best-effort basis.

File-based OAuth credential storage is sensitive. If Codex stores credentials in auth.json, treat that file like a password: do not commit it, paste it into tickets, or share it. Some upstream tools may use an OS keychain depending on platform and config; oauthpy does not abstract that away.

This is not a hosted credential relay. Do not deploy it as a gateway for other users. If you need that, build your own service on top of vendor-approved primitives.

Anthropic compliance note

The official claude-agent-sdk documentation states:

Unless previously approved, Anthropic does not allow third party developers to offer claude.ai login or rate limits for their products, including agents built on the Claude Agent SDK.

oauthpy is a local wrapper for the user's own Claude auth. It does not offer Claude.ai login to other people. If you fork this to build a third-party product that re-distributes Claude.ai access, you need vendor-approved authentication and policy review. See docs/limitations.md.

Development

python -m pip install -e .[dev]
pre-commit install
pytest -m "not live_codex and not live_claude"
ruff check .

Docs:

python -m pip install -e .[docs]
sphinx-build -b html docs docs/_build/html

See docs/development.md for the full developer guide.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oauthpy-1.0.0a1.tar.gz (64.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

oauthpy-1.0.0a1-py3-none-any.whl (39.5 kB view details)

Uploaded Python 3

File details

Details for the file oauthpy-1.0.0a1.tar.gz.

File metadata

  • Download URL: oauthpy-1.0.0a1.tar.gz
  • Upload date:
  • Size: 64.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for oauthpy-1.0.0a1.tar.gz
Algorithm Hash digest
SHA256 566597a6540c3108011983dade93fef9b274911a63115a2a441b841dd7ed8e8c
MD5 78eb3b27b9368bca07c1574bcde17e22
BLAKE2b-256 adbc4922c507d44188c649b37eaf76ff1138372c1796393e98e09707c6cc6446

See more details on using hashes here.

Provenance

The following attestation bundles were made for oauthpy-1.0.0a1.tar.gz:

Publisher: pypi-release.yml on brotherlattice/oauthpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oauthpy-1.0.0a1-py3-none-any.whl.

File metadata

  • Download URL: oauthpy-1.0.0a1-py3-none-any.whl
  • Upload date:
  • Size: 39.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for oauthpy-1.0.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 4a2bc5f8cdf8c0fc945d5f1e68509f455da201ad6242b6fd4ff44d44e2d4fc70
MD5 e1ff442b08da34286c090ba21f8a245d
BLAKE2b-256 1fbec630734d14981a0f55cb0a8422558bb51f6c0d3c0e2233164c32f005410e

See more details on using hashes here.

Provenance

The following attestation bundles were made for oauthpy-1.0.0a1-py3-none-any.whl:

Publisher: pypi-release.yml on brotherlattice/oauthpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page