Authentication¶
codex-open-client uses OAuth 2.0 with PKCE to authenticate against OpenAI's auth server. Tokens are cached at ~/.codex/auth.json (shared with the official Codex CLI).
Authentication Modes¶
Default — Browser + Local Server¶
Opens your browser and starts a local server on localhost:1455 to catch the callback:
Best for local development on a machine with a browser.
No Browser — Print URL + Local Server¶
Prints the URL instead of opening a browser, but still uses the local callback server:
Useful when running over SSH with port forwarding, or when webbrowser.open() doesn't work.
Headless — No Server¶
Prints the URL and prompts the user to paste the callback URL back. No local server needed:
Works anywhere — Docker containers, remote servers, CI environments.
Custom Login Handler¶
Full control over the authentication UX. Your handler receives the OAuth URL and returns the callback URL:
def my_handler(url: str) -> str:
# Show URL to user however you want
print(f"Please visit: {url}")
# Get the callback URL back however you want
return input("Paste redirect URL: ").strip()
client = codex_open_client.CodexClient(login_handler=my_handler)
This is the best option for integrating into a larger application — you control how the URL is presented (GUI dialog, Slack message, email, etc.) and how the callback is collected.
Token Lifecycle¶
- Cache check — loads
~/.codex/auth.json, uses the token if not expired - Refresh — if expired but a refresh token exists, exchanges it for a new access token
- Login — if no valid token and no refresh token, triggers one of the login modes above
All of this happens automatically in the CodexClient constructor. You never need to manage tokens manually.
Custom Token Path¶
Two-Step Login (Advanced)¶
For frameworks where you can't block on user input, use the two-step flow:
# Step 1: Get the OAuth URL
auth = codex_open_client.start_login()
print(auth.url) # Present this to the user
# ... user authenticates in their browser ...
# ... collect the callback URL somehow ...
# Step 2: Exchange the callback for tokens
tokens = codex_open_client.finish_login(auth, callback_url=callback_url)
print(tokens.access_token)
Standalone Functions¶
If you don't need a full client, you can use the auth functions directly: