Use the OpenAI Python SDK with your own ChatGPT subscription
Project description
login-with-chatgpt
Use the official openai Python SDK with your own ChatGPT subscription.
login_with_chatgpt.OpenAI() returns a real openai.OpenAI client while replacing
API-key authentication and transport with ChatGPT OAuth and the Codex backend.
[!WARNING] This package uses private, undocumented ChatGPT Codex endpoints. It is not the public OpenAI API, has no compatibility or availability guarantee, and may stop working when the upstream protocol changes. Requests consume the signed-in user's ChatGPT plan and limits, not OpenAI API credits.
Requirements
- Python 3.11 or newer
- A ChatGPT account with Codex access
- An operating-system keyring supported by
keyring
Codex CLI is not required at runtime. Its source and behavior are protocol references only; no Codex checkout is imported or included in distributions.
Install and sign in
uvx login-with-chatgpt login
uv add login-with-chatgpt
Browser PKCE is the default. For SSH, containers, and other headless environments:
uvx login-with-chatgpt login --device
Credentials are stored in the operating-system keyring. The SDK does not fall back to a plaintext token file. Access tokens are refreshed automatically before expiry and once after an HTTP 401 response.
Confirm the active account and available conversation models:
uvx login-with-chatgpt status
uvx login-with-chatgpt models
uvx login-with-chatgpt doctor
Quick start
from login_with_chatgpt import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-5.6-sol",
input="Explain Python descriptors in three sentences.",
)
print(response.output_text)
client.close()
OpenAI() returns an upstream openai.OpenAI object, so upstream response models,
exceptions, Pydantic parsing, streaming helpers, and function-tool helpers remain
available on the supported endpoints. Async applications use AsyncOpenAI().
from login_with_chatgpt import AsyncOpenAI
async def main() -> None:
client = AsyncOpenAI()
try:
response = await client.responses.create(
model="gpt-5.6-sol",
input="Reply with only: async ok",
)
print(response.output_text)
finally:
await client.close()
Supported API surface
| Python surface | Codex endpoint | Status |
|---|---|---|
client.responses.create() |
POST /responses |
Supported |
client.responses.parse() |
POST /responses |
Supported |
client.responses.stream() |
POST /responses |
Supported |
client.images.generate() |
POST /images/generations |
Supported, non-streaming |
client.images.edit() |
POST /images/edits |
Supported, non-streaming |
ChatGPTAccount().list_models() |
GET /models |
Supported |
| Other upstream resources | Other endpoints | Rejected before network access |
The transport only allows the ChatGPT Codex origin and the methods and paths in
this table. In particular, use ChatGPTAccount().list_models() instead of
client.models.list().
Responses
Verified Responses features are:
- text input and output
- synchronous and asynchronous SSE streaming
- Pydantic structured output through
responses.parse() - function tools and parsed function arguments
- image URL and image data URL input
- function-result continuation
- stateless multi-turn history replay
Structured output
from pydantic import BaseModel
from login_with_chatgpt import OpenAI
class Answer(BaseModel):
summary: str
points: list[str]
client = OpenAI()
response = client.responses.parse(
model="gpt-5.6-sol",
input="Summarize OAuth PKCE.",
text_format=Answer,
)
print(response.output_parsed)
client.close()
Streaming
from login_with_chatgpt import OpenAI
client = OpenAI()
with client.responses.stream(
model="gpt-5.6-sol",
input="Write one short sentence.",
) as stream:
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
client.close()
The Codex Responses endpoint is treated as stateless. The following are rejected rather than silently removed or ignored:
store=Trueprevious_response_idandconversation- background responses
max_output_tokensandmax_completion_tokens- hosted tools other than function tools
- file and audio inputs
GPT Image 2
Image generation and editing use the standalone ChatGPT Codex image endpoints.
The return value remains the upstream openai.types.ImagesResponse model.
Generate an image
import base64
from pathlib import Path
from login_with_chatgpt import OpenAI
client = OpenAI()
result = client.images.generate(
model="gpt-image-2",
prompt="A quiet Tokyo street after rain",
background="opaque",
quality="low",
size="1024x1024",
)
assert result.data and result.data[0].b64_json
Path("tokyo.png").write_bytes(base64.b64decode(result.data[0].b64_json))
client.close()
Edit one or more images
The normal openai-python file interface is preserved. PNG, JPEG, and WebP files
are converted to the data URL JSON format expected by Codex.
import base64
from pathlib import Path
from login_with_chatgpt import OpenAI
client = OpenAI()
with Path("source.png").open("rb") as source:
result = client.images.edit(
model="gpt-image-2",
image=source,
prompt="Change the lighting to late afternoon",
quality="medium",
size="1024x1024",
)
assert result.data and result.data[0].b64_json
Path("edited.png").write_bytes(base64.b64decode(result.data[0].b64_json))
client.close()
The verified image request controls are background, n, quality, size, and
response_format="b64_json". Editing accepts up to five source images, with each
source limited to 50 MiB.
Image streaming, masks, transparent gpt-image-2 backgrounds, other image models,
and unverified output controls are rejected before network access. This includes
output_format, output_compression, partial_images, input_fidelity,
moderation, style, and user.
login-with-chatgpt models intentionally lists conversation models only.
gpt-image-2 is selected directly on client.images and is not inserted into the
server's conversation-model catalog.
Profiles and CLI
login-with-chatgpt --profile work login
login-with-chatgpt profiles
login-with-chatgpt use work
login-with-chatgpt status
login-with-chatgpt models
login-with-chatgpt doctor
login-with-chatgpt logout
Profile precedence is:
- Explicit
--profileor Pythonprofile=argument LOGIN_WITH_CHATGPT_PROFILE- Active profile selected by
login-with-chatgpt use default
Python code can select a profile without changing the CLI default:
from login_with_chatgpt import OpenAI
work = OpenAI(profile="work")
personal = OpenAI(profile="personal")
The library does not rotate profiles automatically. Applications that need account selection or rotation should implement that policy explicitly.
Protocol compatibility
The package version and tested Codex protocol version are independent:
| login-with-chatgpt | Tested Codex protocol | openai-python |
|---|---|---|
0.1.1 |
0.144.1 |
>=2.45.0,<3 |
The tested protocol version is the default. For an urgent compatibility override, use either the environment or the Python constructor:
$env:LOGIN_WITH_CHATGPT_CLIENT_VERSION = "0.145.0"
login-with-chatgpt doctor
from login_with_chatgpt import OpenAI
client = OpenAI(client_version="0.145.0")
doctor reports the effective protocol version and, when installed, the local
Codex CLI version. Codex CLI detection is diagnostic only and never changes the
SDK version automatically.
Development
uv sync --dev
uv run ruff check .
uv run pyright
uv run pytest
uv build
Real-account contract checks are opt-in because they consume subscription usage.
Responses contract test:
$env:LOGIN_WITH_CHATGPT_LIVE_MODEL = "gpt-5.6-sol"
uv run pytest tests/test_live.py -m live
Image generation and edit contract test, which creates two images:
$env:LOGIN_WITH_CHATGPT_LIVE_IMAGE_MODEL = "gpt-image-2"
uv run pytest tests/test_live_images.py -m live
On POSIX shells, use export NAME=value instead of PowerShell's $env:NAME = "value" syntax. Live tests use the currently active credential profile and are
never run by CI.
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 login_with_chatgpt-0.1.2.tar.gz.
File metadata
- Download URL: login_with_chatgpt-0.1.2.tar.gz
- Upload date:
- Size: 76.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a1b7f852e1e3623d17b6c657ca2095e5194379fd91f28badb0175117319021d1
|
|
| MD5 |
7c9bd3bc6f1c75cbc077a59e70854edc
|
|
| BLAKE2b-256 |
094505a9d229345ac1e9a75ee73dd2d76770f74fb9fca262a4aedaa82625eec6
|
File details
Details for the file login_with_chatgpt-0.1.2-py3-none-any.whl.
File metadata
- Download URL: login_with_chatgpt-0.1.2-py3-none-any.whl
- Upload date:
- Size: 35.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9170ddb92cd9a6d6ae3e6a00f7d93af557c3883d4adee7fe7f6ee8cfc32f794
|
|
| MD5 |
11444588ad7a9e649022f794f5839a72
|
|
| BLAKE2b-256 |
48ccf35305362cca10f687945fcd7f9b9bbc1da8c4fdee3768f5f149ee68c38b
|