chatgpt-auth
Sign in to a ChatGPT Plus/Pro/Team account once and get OpenAI access tokens with automatic refresh — for CLIs, bots, and server jobs.
Tokens and refresh tokens are stored on the local filesystem with strict permissions. Nothing about this package talks to OpenAI except the OAuth flow itself.
Install
$ pip install chatgpt-auth
Quick start
Sign in once from a machine with a browser:
$ chatgpt-auth login
Then get an access token anywhere (expired tokens are refreshed and saved automatically):
$ TOKEN=$(chatgpt-auth print-access-token)
$ curl -sS https://api.openai.com/v1/models -H "Authorization: Bearer $TOKEN"
From Python:
from chatgpt_auth import Credentials
credentials = Credentials.load()
token = credentials.get_access_token() # refreshes + saves if needed
Force a refresh or inspect state:
$ chatgpt-auth refresh
$ chatgpt-auth status
$ chatgpt-auth logout
CLI
login— run the browser sign-in (--manualpastes the URL/redirect instead;--replacereplaces an existing connection;--timeout,--port,--agent-nametune the flow).status— show the local connection state (offline, never prints tokens).print-access-token— print the current access token (refreshing first if needed). This is the only command that prints a token.refresh— force a token refresh.logout— wipe local tokens and try to revoke the refresh token remotely. Local sign-out happens even if revocation cannot be confirmed; to fully sign out everywhere also revoke the session in ChatGPT Settings.
All commands take --credentials PATH to point at a credentials file.
Credentials file resolution
Credentials.load() / the CLI resolve the credentials path in this order:
- The explicit
pathargument /--credentialsoption. - The
CHATGPT_AUTH_CREDENTIALSenvironment variable. ${XDG_CONFIG_HOME:-~/.config}/chatgpt-auth/credentials.json(a relativeXDG_CONFIG_HOMEis ignored per the XDG spec).
Relative paths resolve against the current working directory; ~ is
expanded. Reserved aux names (host.json, pending.json, runtime.lock,
login.lock, models.json) are rejected as credentials paths.
Auto refresh and saved tokens
get_access_token() re-checks the store on every call and refreshes when
the token expires within ~60 seconds, saving the new token before
returning it. When a refresh's outcome is unknowable (e.g. the network
died mid-request) the connection is retired rather than risking a
double-submit of a single-use refresh token; the next call raises
ReauthorizationRequiredError and login is required again. A write
failure after a successful refresh returns no token — the object refuses
further use if even retiring the connection cannot be persisted.
Sharing a store with llm-chatgpt-plan
Point --credentials/CHATGPT_AUTH_CREDENTIALS at the existing
credentials.json used by llm-chatgpt-plan to share the same connection,
host.json, pending.json, and both lock files — so sign-ins and token
use in both tools serialize correctly. This package never touches the
models.json model cache; a new connection bumps generation, which is
how llm-chatgpt-plan invalidates its cached model list. Files named
anything other than credentials.json get their own .<name>-suffixed
aux files and share nothing with other stores.
Concurrent use
Multiple processes may hold Credentials for the same path. Refresh
requests collapse onto a shared fcntl.flock runtime lock, so two
processes do not double-submit a refresh. If another process signs out
or signs in underneath you, the next call raises
ReauthorizationRequiredError or ConnectionChangedError.
OS support
macOS and Linux (POSIX fcntl locking). Windows is not supported in this
version.
Security notes
- The credentials directory must be owned by you and not group/world
readable; token files are written
0600. - Tokens, refresh tokens, authorization codes, and PKCE verifiers never appear in logs or exception messages.
logoutclears local state first so an interrupted run still leaves the connection dead, then revokes the refresh token; a broken credentials file is the limit of what local sign-out can guarantee.
API summary
import chatgpt_auth
credentials = chatgpt_auth.Credentials.load() # local file only
token = credentials.get_access_token() # auto refresh + save
token = credentials.refresh() # forced refresh
credentials = chatgpt_auth.login() # browser sign-in
status = chatgpt_auth.status() # AuthStatus (local only)
result = chatgpt_auth.logout() # LogoutResult
Exceptions (chatgpt_auth namespace): SignInRequiredError,
ReauthorizationRequiredError, ConnectionChangedError,
PlanPermissionError, NetworkError, StorageError, LoginTimeoutError,
AuthError, and the base ChatGPTAuthError.
Development
Run from this package directory:
$ uv sync
$ uv run pytest
$ uv run ruff check .
$ uv build
Releases
Publish a GitHub Release tagged chatgpt-auth-<version> matching
project.version in pyproject.toml. The first release tag is
chatgpt-auth-0.1.0. The publish-chatgpt-auth.yml workflow verifies the
tag, tests Python 3.11–3.14, builds this package's wheel and sdist, and
publishes them to PyPI using Trusted Publishing. Releases for other
packages are skipped.
Metadata
Release files for chatgpt-auth 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| chatgpt_auth-0.1.0.tar.gz | 46.2 kB | With provenance | Details for chatgpt_auth-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| chatgpt_auth-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for chatgpt_auth-0.1.0-py3-none-any.whl |
Total release size: 78.6 kB
Release files / chatgpt_auth-0.1.0.tar.gz
| Download URL | chatgpt_auth-0.1.0.tar.gz |
|---|---|
| Size | 46.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d095e22c35db974f17a74ce56a0708103bc3c0d68b83507411b20364a3ca8927
|
|
BLAKE2b-256 checksum How to use checksums |
3d3ee5286739ced3bd31a9cebd6dd7ce7e9bb0408976d453a8fb874dca63efe6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / chatgpt_auth-0.1.0-py3-none-any.whl
| Download URL | chatgpt_auth-0.1.0-py3-none-any.whl |
|---|---|
| Size | 32.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
18a8b836cb2e50c91200042f8a41608db871f9bc564abeaa81674b7a1f477cef
|
|
BLAKE2b-256 checksum How to use checksums |
bc7a51f4e2cfec7833d2de61d0beb1e5d4490100f60196d943c6e170d97d34f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logSecurity for chatgpt-auth 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for chatgpt_auth-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.