Skip to main content

Local auth surface manager for LLM API keys and OAuth tokens.

Project description

llm-auth

llm-auth is a local credential manager for LLM developer tools. It keeps API-key and subscription-OAuth credentials in an ignored project .env file, with metadata that makes each auth surface discoverable, testable, and refreshable.

It is built for local workflows where scripts, benchmarks, and agent tools need model access without committing secrets or scattering credentials across many ad hoc files.

What It Supports

  • API-key surfaces for providers such as OpenAI and OpenRouter.
  • ChatGPT subscription OAuth through LiteLLM's ChatGPT provider.
  • Redacted credential status checks.
  • Lightweight auth validation.
  • OAuth token refresh for renewable surfaces.
  • Repo-local .env auth storage with explicit metadata envelopes.

Install

pip install llm-auth

ChatGPT subscription OAuth uses LiteLLM's ChatGPT provider. Install the extra when you want llm-auth login chatgpt:

python -m pip install 'llm-auth[chatgpt]'

After installation, use the llm-auth command:

llm-auth status

Mental Model

A surface is a named auth target, such as chatgpt, research, or evals. Each surface has an auth mode:

  • api-key: a provider key stored in a named env var.
  • subscription-oauth: a renewable OAuth record managed through LiteLLM.

llm-auth stores those surfaces in .env as metadata envelopes. The env file must be ignored by version control.

Before using an existing .env, llm-auth checks that the file is not readable by group or other users. In Git, Sapling, and Mercurial repositories, it also checks that the file is ignored, not currently tracked, and not present in commit history.

Common Workflows

ChatGPT Subscription OAuth

# Create or refresh the ChatGPT subscription OAuth surface.
llm-auth login chatgpt

# Show redacted status for the ChatGPT surface.
llm-auth status chatgpt

# Validate the ChatGPT auth state without printing secrets.
llm-auth test chatgpt

login chatgpt uses LiteLLM's ChatGPT authenticator. LiteLLM owns the device-code flow and token exchange; llm-auth stores the resulting auth record in .env as CHATGPT_AUTH_JSON.

If LiteLLM is not installed, llm-auth login chatgpt prints the install command:

python -m pip install 'llm-auth[chatgpt]'

If the stored access token is still valid, llm-auth login chatgpt exits with ok. If a refresh token exists, it attempts refresh before opening a new device-code login.

When you already have refreshable OAuth state, renew without opening a browser:

# Refresh only the ChatGPT subscription OAuth surface.
llm-auth renew chatgpt

Device codes are sensitive while active. Never share them.

API-Key Surface

Create an API-key surface:

# Create a research surface for OpenAI. The default env var template is
# <PROVIDER>_<SURFACE>_API_KEY, so this uses OPENAI_RESEARCH_API_KEY.
llm-auth add-api-key research openai --model gpt-4.1-mini

This appends an empty env assignment to .env:

# BEGIN LLM AUTH SURFACE research api-key
# surface=research
# provider=openai
# auth=api-key
# env=OPENAI_RESEARCH_API_KEY
# model=gpt-4.1-mini
OPENAI_RESEARCH_API_KEY=
# END LLM AUTH SURFACE research api-key

Fill in the key manually, then check it:

# Show redacted status for every configured surface.
llm-auth status

# Test every configured surface.
llm-auth test

# Test only the research surface.
llm-auth test research

Use a specific env var when a provider already has a conventional name:

# Create an OpenRouter surface backed by OPENROUTER_API_KEY.
llm-auth add-api-key evals openrouter \
  --env OPENROUTER_API_KEY \
  --api-base https://openrouter.ai/api/v1 \
  --model openrouter/openai/gpt-5.4-mini

Use --key only when you intentionally want the command to write the secret:

llm-auth add-api-key research openai \
  --model gpt-4.1-mini \
  --key "$OPENAI_RESEARCH_API_KEY"

API-key surfaces do not use login or renew. Rotate them by changing the configured env var value.

LiteLLM App Integration

Apps that use LiteLLM can treat .env as the local auth bootstrap file.

For API-key surfaces, load .env before creating LiteLLM requests and read the configured env var, such as OPENAI_RESEARCH_API_KEY or OPENROUTER_API_KEY. The metadata envelope tells your app which provider, model, API base, and env var belong to a surface.

For ChatGPT subscription OAuth, load .env so CHATGPT_AUTH_JSON is present, then install the llm-auth ChatGPT/LiteLLM integration before making chatgpt/... calls. That integration makes LiteLLM read and refresh the auth record from .env instead of its default token file.

Command Reference

llm-auth status

Show redacted status for all discovered surfaces:

# Show every API-key and OAuth surface discovered in .env.
llm-auth status

Show one surface:

# Show only ChatGPT subscription OAuth status.
llm-auth status chatgpt

# Show only an API-key surface named research.
llm-auth status research

Example ChatGPT status:

{
  "chatgpt": {
    "access_token": true,
    "account_id": true,
    "auth": "subscription-oauth",
    "auth_json": true,
    "env": "CHATGPT_AUTH_JSON",
    "expired": false,
    "refresh_token": true
  }
}

Example API-key status:

{
  "research": {
    "api_key": true,
    "auth": "api-key",
    "env": "OPENAI_RESEARCH_API_KEY",
    "provider": "openai"
  }
}

Status output reports whether credentials are present, but does not print secret values.

llm-auth test

Run lightweight checks for all discovered surfaces:

# Test every configured auth surface discovered in .env.
llm-auth test

Run detailed checks for one surface:

# Test only ChatGPT subscription OAuth state.
llm-auth test chatgpt

# Test only an API-key surface named research.
llm-auth test research

For ChatGPT subscription OAuth, the default test checks that CHATGPT_AUTH_JSON exists and contains usable OAuth state. The ChatGPT backend completion path is Cloudflare-gated and is not part of the documented OpenAI API, so the live completion check is opt-in. Add live_backend=true to the chatgpt surface envelope only when you explicitly want llm-auth test chatgpt to send a live backend prompt.

For OpenAI API-key surfaces, llm-auth test calls the OpenAI /models endpoint so corrupted keys fail even when no model is configured. When a model is declared, it also checks model access and sends a small prompt through the official OpenAI Responses API:

llm-auth test research --model gpt-4.1-mini
llm-auth test --surface-model research=gpt-4.1-mini

llm-auth login

Create or refresh a managed login surface:

# Run the ChatGPT subscription OAuth login flow.
llm-auth login chatgpt

Today, login is for ChatGPT subscription OAuth. API-key surfaces are created with add-api-key.

llm-auth renew

Refresh renewable OAuth surfaces without a new browser/device-code flow:

# Refresh every renewable auth surface discovered in .env.
llm-auth renew

# Refresh only ChatGPT subscription OAuth.
llm-auth renew chatgpt

Use login when you need to create a new auth surface or complete a new browser/device-code flow. Use renew when a surface already has refreshable OAuth state.

llm-auth add-api-key

Create an API-key metadata envelope:

llm-auth add-api-key <surface> <provider>

Useful options:

  • --env: choose the env var name.
  • --model: record default model metadata for tests and consumers.
  • --api-base: record provider API base metadata.
  • --key: write the secret value directly.
  • --allow-unignored: allow writing to an env file that is not ignored.

By default, llm-auth refuses to write credentials unless the target is an ignored repo-root .env. Use --allow-unignored only for deliberate temporary setups; it does not bypass checks for unsafe file permissions, tracked files, or committed history.

Auth Store Format

llm-auth treats .env as a bootstrapping auth store. Each auth surface is wrapped in a metadata envelope:

# BEGIN LLM AUTH SURFACE research api-key
# surface=research
# provider=openai
# auth=api-key
# env=OPENAI_RESEARCH_API_KEY
# model=gpt-5.4-mini
# renew=false
OPENAI_RESEARCH_API_KEY=...
# END LLM AUTH SURFACE research api-key

The .env file should be ignored by version control. llm-auth sets file mode 0600 when it writes the file, where supported by the operating system. If an existing .env has broader permissions, fix it before running commands:

chmod 600 .env

Security Notes

  • Do not commit .env or copied credential values.
  • Keep .env ignored and untracked. llm-auth refuses to use it when Git, Sapling, or Mercurial reports that it is tracked or appears in commit history.
  • Prefer leaving --key out and filling the secret manually when possible.
  • Treat device codes as temporary secrets.
  • llm-auth status redacts credential presence and does not print secret values.
  • llm-auth is local tooling, not a hosted secret manager.

Requirements

  • Python 3.11 or newer.
  • LiteLLM, installed as a package dependency.

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

llm_auth-0.1.2.tar.gz (24.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

llm_auth-0.1.2-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file llm_auth-0.1.2.tar.gz.

File metadata

  • Download URL: llm_auth-0.1.2.tar.gz
  • Upload date:
  • Size: 24.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for llm_auth-0.1.2.tar.gz
Algorithm Hash digest
SHA256 522a536f16c78f172ad498b4d0e74165cda5bf89fd226f2ae79fa07e99d50649
MD5 95b3648c3fd7bf06b95e68f305f94186
BLAKE2b-256 69584e08ab77cdcb51ce0ca0937d504301d23225327a780fb4c7121fdcba790a

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_auth-0.1.2.tar.gz:

Publisher: publish.yml on omry/llm-auth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file llm_auth-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: llm_auth-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for llm_auth-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 53b6da06928c0ede21311473ece1baf49ef4676eb42a8272dc8560bf7f9d1115
MD5 69b7040429cf4c712137b25eb0f9c4ca
BLAKE2b-256 b08d8976cd2e38ee5673e1e07919a1d35144640a0585bb016a22f38573776d55

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_auth-0.1.2-py3-none-any.whl:

Publisher: publish.yml on omry/llm-auth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page