ChatGPT OAuth integration for the openai_codex model provider.
Thin orchestration layer over langchain_openai.chatgpt_oauth. Reuses the
upstream PKCE/token primitives directly (_generate_pkce_pair,
_build_authorize_url, _CallbackHandler, _post_form,
_token_from_response, _FileChatGPTOAuthTokenProvider) so this module only
adds:
login_chatgpt
uses print(), which is invisible inside a Textual app),_wait_for_oauth_callback), and/auth to read sign-in status, expiry, and the linked account
without re-implementing token parsing.The browser-loopback flow mirrors the MCP one in mcp_auth from the user's
POV ā PKCE + state CSRF + browser launch with a manual-URL fallback ā but
the callback server here is upstream's single-threaded polling
http.server.HTTPServer (reused via _CallbackHandler), not the
ThreadingHTTPServer that mcp_auth runs itself. The OAuth-specific parts
(token exchange, refresh, file storage with 0600 perms) are delegated to
upstream.
The OAuth primitives are reused from langchain-openai>=1.3.1, which is
the first release to ship langchain_openai.chatgpt_oauth. This module
deliberately reaches into upstream-internal (_-prefixed) helpers; their
stability is an upstream concern, so pin the minimum langchain-openai
version when bumping and re-check the imported names against the release.
Return the ChatGPT OAuth token store path.
Stored under Deep Agents' own state dir
(~/.deepagents/.state/chatgpt-auth.json) so the credential lives
alongside the rest of the app's state rather than in langchain_openai's
default ~/.langchain.
Return the current ChatGPT OAuth sign-in state.
Reads the on-disk token without triggering a refresh (a passive
inspect, suitable for switcher labels and the /auth manager). If a
refresh is needed for actual usage, callers should construct a
_FileChatGPTOAuthTokenProvider and call get_token() instead.
Return whether a ChatGPT OAuth token is stored on disk.
Delete the stored ChatGPT OAuth token.
Run the ChatGPT OAuth Authorization Code Flow with PKCE.
Reimplements the upstream langchain_openai.chatgpt_oauth browser
sign-in flow over its lower-level helpers, but routes the authorize-URL
display through interaction so a Textual screen can render it inline.
The blocking callback wait and the synchronous token exchange both run
inside asyncio.to_thread so the calling event loop stays responsive.
Construct a _ChatOpenAICodex model wired to the on-disk token store.
Snapshot of the ChatGPT OAuth login state.
Raised when the user cancels a sign-in flow mid-callback wait.
Raised when a stored ChatGPT token cannot be refreshed.
Distinct from a missing token (FileNotFoundError): a token exists on
disk but its refresh token was revoked or expired, so an automatic
refresh failed and the user must sign in again. create_model maps this
to a MissingCredentialsError that points at /auth.
UI hooks for the browser loopback sign-in flow.
Implementations decide how to surface the authorize URL and whether to auto-open a browser. The Textual screen subclasses this; CLI / headless callers can supply a minimal stdout-based implementation.
The default base class implements the print-to-stdout fallback so it
works for headless tests and the -x non-interactive path; UI callers
override show_authorize_url.