Skip to main content
ChatCLI supports authentication via OAuth 2.0 with PKCE and Device Flow (RFC 8628) for providers that offer these options. This allows you to use your existing plan (such as ChatGPT Plus, Codex, Claude Pro, or GitHub Copilot) directly in the terminal, without needing to generate or paste API keys.

Authentication Methods

Both methods can coexist. ChatCLI prioritizes OAuth credentials when both are available.
OAuth support varies by provider. Only OpenAI, Anthropic, and GitHub Copilot support OAuth login via /auth login. All other providers — GoogleAI, xAI, ZAI, MiniMax, Moonshot (Kimi), StackSpot, and Ollama — require authentication via API key (set in .env or environment variables).

/auth Commands

All authentication commands have auto-completion — just type /auth and press Tab.

View Status

Displays the authentication status of all configured providers, including credential type (API Key vs OAuth), token validity, and source.

Login via OAuth

1

Browser opens automatically

The browser opens to the provider’s login page.
2

Authorize access

OpenAI: a local HTTP server captures the callback automatically (port 1455).Anthropic: after authorizing, copy the code displayed on the page and paste it in the terminal.GitHub Copilot: enter the device code displayed in the terminal on the GitHub page.
3

Provider available immediately

The provider appears immediately in /switchno app restart needed.

Supported Providers

Logout

Removes the stored OAuth credentials for the specified provider.

Technical Details of OAuth Flows

This section describes how each OAuth flow works internally, including URLs, parameters, and ChatCLI behavior.

Anthropic OAuth (PKCE + Manual Code)

The Anthropic flow uses OAuth 2.0 with PKCE (Proof Key for Code Exchange) and a manual copy-paste mechanism for the authorization code.
1

PKCE generation and browser launch

ChatCLI generates a random code_verifier and computes the code_challenge using SHA-256 (method S256). The browser opens to the authorization URL with the required parameters.
2

User authorizes in browser

The user logs into Claude and authorizes access. The console page displays a code in the format code#state.
3

User pastes code in terminal

ChatCLI prompts the user to paste the displayed code. The portion after the # is the state parameter, used in the token exchange.
4

Code exchanged for tokens

ChatCLI sends the code, state, and code_verifier to the token endpoint and receives an access_token + refresh_token.
The token exchange uses a plain http.Client (no custom transport) to avoid TLS fingerprinting issues with Cloudflare. The User-Agent: claude-cli/2.1.2 (external, cli) header is required. Using an HTTP client with LoggingTransport or a custom transport causes rejection by Anthropic’s CDN.
Token refresh also uses the plain http.Client and the same User-Agent, for the same reason.

OpenAI Codex OAuth (PKCE + Localhost Callback)

The OpenAI flow uses OAuth 2.0 with PKCE and a local HTTP server to automatically capture the callback.
1

Local server starts on port 1455

ChatCLI starts an HTTP server at http://localhost:1455 to receive the OAuth callback.
2

Browser opens to authorization page

The browser opens to the OpenAI authorization URL with the PKCE challenge and a state parameter for CSRF validation.
3

User authorizes in browser

After login and authorization, the browser redirects to http://localhost:1455/auth/callback with the authorization code.
4

CSRF validation and token exchange

The local server validates the state parameter against the originally generated value (CSRF protection), exchanges the code for tokens, and shuts down the server.
Token refresh is automatic and uses the standard HTTP client with logging.

GitHub Copilot Device Flow (RFC 8628)

GitHub Copilot uses the Device Authorization Grant (RFC 8628), a flow designed for devices without an integrated browser, such as CLI terminals.
1

Request device code

ChatCLI requests a device_code and a user_code from the GitHub endpoint.
2

Display code in terminal

ChatCLI displays the user_code and the verification URL (https://github.com/login/device) to the user.
3

User authorizes in browser

The user visits the URL, enters the user_code, and authorizes ChatCLI access.
4

Polling until authorization

ChatCLI polls the token endpoint every 5 seconds until it receives the access token or a terminal error.
Polling responses:
GitHub Copilot tokens are non-expiring and do not have a refresh token. They persist until manually revoked on the GitHub settings page.

Complete Flow: From Zero to First Prompt

If you are starting without any configured credentials, follow these steps:
1

Start ChatCLI

Works even without configured credentials.
2

Log in via OAuth

3

Authorize in the browser

The browser opens automatically to the provider’s login page.
4

Switch to the provider

5

Send your first prompt


Automatic Endpoint Routing (OpenAI)

ChatCLI automatically detects the credential type and routes requests to the correct endpoint:
You don’t need to configure anything — routing is automatic based on the token type.
On the Codex backend, ChatCLI also sends the client-identification headers the backend requires (originator plus a Codex User-Agent). Newer model slugs — such as the GPT-5.6 family (gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna) — are only served when both headers are present; without them the backend answers 404 Model not found (Luna, for example, has no server-side fallback).

Credential Storage

OAuth credentials are saved with AES-256-GCM encryption at:

Encryption Details

The encryption key is automatically generated and stored at ~/.chatcli/.auth-key. Unencrypted data from previous versions is automatically detected (absence of the chatcli-enc:v1: prefix) and migrated to the encrypted format on the next save. Each stored profile contains:
  • Access token (encrypted)
  • Refresh token (encrypted, when applicable)
  • Expiry (timestamp in milliseconds)
  • Account ID and email from the provider
  • Provider type (anthropic, openai-codex, github-copilot)
To customize the storage directory, set the environment variable:

Token Validation

ChatCLI implements strict OAuth token validation to prevent use of invalid or expired credentials:

Access Token Validation

  • Empty access token rejection — Tokens with an empty access token are rejected immediately, without attempting requests. This prevents confusing “unauthorized” errors when credentials are corrupted.
  • Expiry validation — The expiry field is checked before each request. Expired tokens trigger the refresh flow automatically.

Maximum Token Lifetime (CHATCLI_MAX_TOKEN_LIFETIME)

For production environments with compliance requirements, you can limit the maximum token lifetime:
When the maximum lifetime is reached, the token is invalidated and the user must log in again via /auth login. This ensures periodic credential rotation even when the refresh token is still valid.

Automatic Token Refresh

ChatCLI automatically renews expired tokens in two layers:

Proactive Refresh

When resolving credentials for a request, ChatCLI checks if the token is expired (IsExpired()) or about to expire (IsExpiringSoon() with a 5-minute margin). If so, the refresh is executed before the request.

Reactive Refresh

If a request returns an HTTP 401 error, ChatCLI invalidates the credential cache, performs the token refresh, recreates the HTTP client, and retries the request automatically — all transparent to the user.
The 5-minute safety margin before actual expiry prevents race conditions where the token expires between the check and the request being sent.
GitHub Copilot tokens (Device Flow) do not expire and do not have a refresh token — they persist until manually revoked.

External CLI Sync

ChatCLI can import credentials from external CLIs via SyncExternalCliCreds():
Import only occurs if the external credentials are fresher than those already stored. This ensures that a login performed directly in ChatCLI is not overwritten by stale data from another CLI.

Credential Resolution Priority

When determining which credential to use for a provider, ChatCLI follows this priority order:
1

Auth-profiles store (OAuth/Token)

OAuth credentials stored in auth-profiles.json, including profiles synced from external CLIs. Automatic refresh is applied at this layer.
2

Environment variables

Variables such as ANTHROPIC_OAUTH_TOKEN, ANTHROPIC_API_KEY, OPENAI_API_KEY, and GITHUB_COPILOT_TOKEN.
Prefix system: credential values may include prefixes that signal the type to the provider:

Advanced Configuration


Troubleshooting

The Anthropic flow redirects to the console page that displays the authorization code in the format code#state. Copy the full text (including the part after the #) and paste it in the terminal when prompted. ChatCLI separates the code from the state automatically.
This typically occurs when a custom HTTP client (with LoggingTransport) is used. ChatCLI uses a plain http.Client for Anthropic token exchange to avoid TLS fingerprinting by Cloudflare. If you are developing, ensure that the exchangeAnthropicToken function uses a client without a custom transport.
Run /auth status to verify that the token was saved correctly. If needed, try /auth logout <provider> followed by /auth login <provider>.
Make sure your GitHub account has an active Copilot subscription (Individual, Business, or Enterprise). Check at https://github.com/settings/copilot if Copilot is enabled.
The device code has limited validity. If polling exceeds 15 minutes without authorization, the code expires. Run /auth login github-copilot again to generate a new code.
OAuth tokens are automatically renewed in two ways:
  • Proactively: when resolving credentials, if the token is expired or within the 5-minute margin, a refresh is attempted before the request.
  • Reactively: if a request returns a 401 error, ChatCLI invalidates the credential cache, attempts to refresh the OAuth token, recreates the client, and retries the request automatically.
If both attempts fail (e.g., refresh token is also expired), log in again with /auth login.GitHub Copilot tokens (Device Flow) do not expire and do not have a refresh token — they are persistent until manually revoked.

Next Steps

Command Reference

Complete list of all available commands.

Configuration (.env)

All available environment variables.

Basic Usage

Learn the fundamentals of ChatCLI.