ChatGPT (Codex) OAuth transport for Axio using Responses API
Project description
axio-transport-codex
ChatGPT OAuth transport for axio using the OpenAI Responses API.
Authenticates via the same OAuth2 PKCE flow used by the ChatGPT desktop client - no API key purchase required; your ChatGPT subscription covers usage. Implements the OpenAI Responses API (not the legacy chat completions endpoint).
Features
- No API key purchase - authenticates with your ChatGPT account via OAuth2 PKCE
- Responses API - uses OpenAI's newer Responses endpoint (
/backend-api/codex/responses) - Automatic token refresh - access tokens are silently refreshed before expiry; callers notified via
on_auth_refresh - Full streaming - incremental text, reasoning, and tool-call events via SSE
- Tool calling - works with all axio tool handlers; parallel tool calls enabled
- Retry logic - automatic backoff on 429 and 5xx responses; honours
Retry-Afterheader - aiohttp-based - non-blocking I/O throughout
Installation
pip install axio-transport-codex
With the TUI settings screen (ChatGPT sign-in dialog):
pip install "axio-transport-codex[tui]"
Authentication
CodexTransport authenticates with ChatGPT using OAuth2 PKCE. The transport stores an access token (api_key), a refresh token, and an expiry timestamp. It refreshes the access token automatically when it is within 30 seconds of expiry.
Running the OAuth flow
Use run_oauth_flow() from axio_transport_codex.oauth to obtain tokens for the first time. It opens a browser window for ChatGPT sign-in and waits for the callback on http://localhost:1455/auth/callback.
import asyncio
from axio_transport_codex.oauth import run_oauth_flow
from axio_transport_codex import CodexTransport
async def main() -> None:
tokens = await run_oauth_flow()
# tokens = {
# "access_token": "...",
# "refresh_token": "...",
# "expires_at": "1234567890", # Unix timestamp as string
# "account_id": "...",
# }
transport = CodexTransport(
api_key=tokens["access_token"],
refresh_token=tokens["refresh_token"],
expires_at=tokens["expires_at"],
account_id=tokens["account_id"],
)
Persisting tokens across sessions
Pass an on_auth_refresh callback to receive updated credentials whenever the access token is refreshed. Save the returned dict to disk or a secrets store and restore it on the next run.
import json, pathlib, aiohttp
from axio_transport_codex import CodexTransport
CRED_FILE = pathlib.Path("~/.config/axio/codex.json").expanduser()
async def save_tokens(tokens: dict[str, str]) -> None:
CRED_FILE.parent.mkdir(parents=True, exist_ok=True)
CRED_FILE.write_text(json.dumps(tokens))
async def main() -> None:
creds = json.loads(CRED_FILE.read_text()) if CRED_FILE.exists() else {}
async with aiohttp.ClientSession() as session:
transport = CodexTransport(
api_key=creds.get("api_key", ""),
refresh_token=creds.get("refresh_token", ""),
expires_at=creds.get("expires_at", ""),
account_id=creds.get("account_id", ""),
session=session,
on_auth_refresh=save_tokens,
)
# use transport with an Agent ...
Refreshing tokens manually
from axio_transport_codex.oauth import refresh_access_token
tokens = await refresh_access_token(refresh_token="...")
# tokens = {"access_token": ..., "refresh_token": ..., "expires_at": ..., "account_id": ...}
Usage
import asyncio
import aiohttp
from axio.agent import Agent
from axio.context import MemoryContextStore
from axio.events import TextDelta
from axio_transport_codex import CodexTransport, CODEX_MODELS
async def main() -> None:
async with aiohttp.ClientSession() as session:
transport = CodexTransport(
api_key="<your-chatgpt-access-token>",
refresh_token="<your-refresh-token>",
expires_at="<unix-timestamp-string>",
account_id="<your-account-id>",
model=CODEX_MODELS["gpt-4.1"],
session=session,
)
agent = Agent(system="You are a helpful assistant.", tools=[], transport=transport)
ctx = MemoryContextStore()
async for event in agent.run_stream("Explain the Rust borrow checker.", ctx):
if isinstance(event, TextDelta):
print(event.delta, end="", flush=True)
print()
asyncio.run(main())
The session parameter is required for streaming. Create an aiohttp.ClientSession in an async context and pass it to the transport.
Configuration reference
CodexTransport is a dataclass with the following fields:
| Field | Type | Default | Description |
|---|---|---|---|
name |
str |
"ChatGPT (Codex)" |
Display name (used by TUI) |
api_key |
str |
"" |
ChatGPT OAuth access token |
refresh_token |
str |
"" |
OAuth refresh token for silent renewal |
expires_at |
str |
"" |
Access token expiry as a Unix timestamp string |
account_id |
str |
"" |
ChatGPT account/organisation ID (sent as ChatGPT-Account-ID header) |
base_url |
str |
"https://chatgpt.com/backend-api/codex" |
API base URL |
model |
ModelSpec |
CODEX_MODELS["gpt-4.1"] |
Active model |
models |
ModelRegistry |
all CODEX_MODELS |
Available models |
session |
aiohttp.ClientSession | None |
None |
HTTP session (required for streaming) |
on_auth_refresh |
Callable[[dict[str, str]], Awaitable[None]] | None |
None |
Callback invoked with fresh credentials after token refresh |
max_retries |
int |
10 |
Maximum retry attempts on 429 / 5xx |
retry_base_delay |
float |
5.0 |
Base delay in seconds for exponential backoff |
Models
| Model ID | Context | Max output | Capabilities |
|---|---|---|---|
gpt-4.1 |
1,047,576 | 32,768 | text, vision, tool use |
gpt-4.1-mini |
1,047,576 | 32,768 | text, vision, tool use |
gpt-4.1-nano |
1,047,576 | 32,768 | text, tool use |
gpt-4o |
128,000 | 16,384 | text, vision, tool use |
gpt-4o-mini |
128,000 | 16,384 | text, vision, tool use |
o4-mini |
200,000 | 100,000 | text, reasoning, tool use |
o3 |
200,000 | 100,000 | text, reasoning, tool use |
o3-mini |
200,000 | 100,000 | text, reasoning, tool use |
The default model is gpt-4.1.
fetch_models()
await transport.fetch_models() queries the Codex /models endpoint for the list of models your account has access to. If the request fails or the account is not configured, it falls back to the built-in CODEX_MODELS registry. Models not found in the built-in registry are added with basic text and tool_use capabilities.
session and api_key must be set before calling fetch_models().
Plugin registration
When installed, this package registers itself via entry points so axio-tui discovers it automatically:
[project.entry-points."axio.transport"]
codex = "axio_transport_codex:CodexTransport"
[project.entry-points."axio.transport.settings"]
codex = "axio_transport_codex.tui:CodexSettingsScreen"
Part of the axio ecosystem
axio · axio-transport-openai · axio-transport-anthropic · axio-tui
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file axio_transport_codex-0.9.7.tar.gz.
File metadata
- Download URL: axio_transport_codex-0.9.7.tar.gz
- Upload date:
- Size: 90.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7ab69e3b985aa4651fef4cd23a11ee4dce3c594c2d3e95aaaedab8c6856670b
|
|
| MD5 |
a2e2b8aaeef03860f7254ff9e890b3a6
|
|
| BLAKE2b-256 |
5b48ba3fcbb0a80f2150248e5649b1c0298369abb5d3c913e1aaf9121bfda4c1
|
Provenance
The following attestation bundles were made for axio_transport_codex-0.9.7.tar.gz:
Publisher:
publish.yml on mosquito/axio-agent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axio_transport_codex-0.9.7.tar.gz -
Subject digest:
c7ab69e3b985aa4651fef4cd23a11ee4dce3c594c2d3e95aaaedab8c6856670b - Sigstore transparency entry: 1608226659
- Sigstore integration time:
-
Permalink:
mosquito/axio-agent@6ff39bea9f358856230d6a7a819f3d3e03c16e6d -
Branch / Tag:
refs/tags/0.9.7 - Owner: https://github.com/mosquito
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6ff39bea9f358856230d6a7a819f3d3e03c16e6d -
Trigger Event:
release
-
Statement type:
File details
Details for the file axio_transport_codex-0.9.7-py3-none-any.whl.
File metadata
- Download URL: axio_transport_codex-0.9.7-py3-none-any.whl
- Upload date:
- Size: 15.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ade5e9f9c60014ee8e2dbbaac06bb3297907e60d2147a9e6102a5737e6d6d78
|
|
| MD5 |
a5b39e85f6cdf114bb789d2493f25a24
|
|
| BLAKE2b-256 |
041030843d5f896dcbedab9101efafd2b9694bf4d0f39a4f63b28bdaa2d7c7ea
|
Provenance
The following attestation bundles were made for axio_transport_codex-0.9.7-py3-none-any.whl:
Publisher:
publish.yml on mosquito/axio-agent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axio_transport_codex-0.9.7-py3-none-any.whl -
Subject digest:
3ade5e9f9c60014ee8e2dbbaac06bb3297907e60d2147a9e6102a5737e6d6d78 - Sigstore transparency entry: 1608226764
- Sigstore integration time:
-
Permalink:
mosquito/axio-agent@6ff39bea9f358856230d6a7a819f3d3e03c16e6d -
Branch / Tag:
refs/tags/0.9.7 - Owner: https://github.com/mosquito
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6ff39bea9f358856230d6a7a819f3d3e03c16e6d -
Trigger Event:
release
-
Statement type: