Claude OAuth Provider
The claude-oauth provider authenticates with a Claude Code subscription via OAuth and mimics the Claude Code CLI’s exact request shape, headers, and request signing. Use this when you have a Claude Code subscription instead of a per-token Claude API key. For the direct Messages API, see claude-api.
Note: This provider replicates Claude Code’s fingerprinting and attestation machinery exactly. Modifying the request body, headers, or OAuth flow will cause requests to be rejected by Anthropic. If you hit 401/403 errors, verify that no middleware is rewriting the request.
Configuration
| Setting | Value |
|---|---|
Profile type | claude-oauth |
| Default base URL | https://api.anthropic.com |
| Credential | OAuth bundle stored in the database (acquired via meka provider add / login) |
| Auth method | Authorization: Bearer <oauth_token> |
| API version | 2023-06-01 |
Quickest Start
meka provider add work --type claude-oauth --model claude-opus-4-6
meka provider add opens your browser, walks you through authorization, and saves the tokens to the
local database. It also writes the [providers.work] profile and sets it as the default.
Config File
meka provider add writes this for you; you can also edit it by hand (secrets stay in the database):
default_provider = "work"
[providers.work]
type = "claude-oauth"
model = "claude-opus-4-6"
effort = "high" # optional; "low" | "medium" | "high"
redact_thinking = true # optional; default on, matching Claude Code
# device_id, oauth_token_url, client_id are all optional overrides
See Configuration → Config File for the full list of fields.
Provider-specific knobs
effort
Sent as output_config.effort for effort-capable models (opus-4-6, sonnet-4-6). Accepts "low", "medium", or "high". Defaults to "high". Mirrors Claude Code’s effort knob in utils/effort.ts. Older models (Sonnet 4.0, Opus 4.1, Haiku 4.5) ignore this field on the wire and the body field is omitted automatically.
redact_thinking
Adds the redact-thinking-2026-02-12 beta header for capable models, matching Claude Code, which sends it by default. With it on, the server withholds the readable chain of thought: thinking blocks come back with empty text plus a signature, and any redacted_thinking blocks carry an opaque data payload. meka preserves and replays both verbatim, so multi-turn reasoning continuity is maintained. The practical effect is that live thinking output goes quiet for these models (there is no readable text to show), exactly as in Claude Code. Defaults to true; set redact_thinking = false to drop the beta and keep interleaved thinking visible.
device_id
Stable per-machine identifier embedded in metadata.user_id to mirror Claude Code’s ~/.claude.json device ID (getOrCreateUserID in utils/config.ts).
If unset, meka first tries to adopt userID from ~/.claude.json (so meka and Claude Code on the same machine present as the same device). If that file is missing or has no userID, meka generates a 64-character hex string. Either way the resolved value is persisted back to [providers.<name>].device_id in config.toml. Other backends ignore this field; no stub config file is written for them.
client_id
Optional override for the OAuth client ID. Defaults to Claude Code’s client ID; rarely needed.
Authentication
OAuth login
meka provider add (and meka provider login <name> to re-authenticate) performs an OAuth 2.0 Authorization Code flow with PKCE:
- meka generates a PKCE challenge and opens your browser to Claude’s authorization page.
- You authorize the application in your browser.
- You paste the authorization code back into meka (the redirect URI is the platform.claude.com hosted callback page, not a local listener).
- meka exchanges the code for access + refresh tokens.
- Tokens are stored in the local database and refreshed automatically.
The OAuth client ID defaults to Claude Code’s client ID but can be overridden per profile via client_id.
Token Lifecycle
- Acquire the initial token with
meka provider add/login. - The token bundle is stored in the database, keyed by the profile name.
- On subsequent launches the token is loaded from the database.
- meka refreshes the access token automatically when it’s within 5 minutes of expiry; the new token is written back to the database under the same profile.
- If the refresh token dies, run
meka provider login <name>to re-authenticate.
Token refresh URL: defaults to https://api.anthropic.com/v1/oauth/token. Configurable via oauth_token_url in the profile.
Supported Models
Any model your Claude Code subscription exposes. Current line-up (per Anthropic’s models overview):
| Family | Alias | Notes |
|---|---|---|
| Opus 4.7 | claude-opus-4-7 | Latest Opus; most capable, no extended-thinking, adaptive thinking |
| Sonnet 4.6 | claude-sonnet-4-6 | Latest Sonnet, speed + intelligence balance |
| Haiku 4.5 | claude-haiku-4-5 | Latest Haiku, fastest |
Older but still available: claude-opus-4-6, claude-sonnet-4-5, claude-opus-4-5, claude-opus-4-1. Deprecated and retiring 2026-06-15: claude-opus-4-20250514, claude-sonnet-4-20250514.
meka forwards the model string verbatim; it doesn’t gate which strings are valid. Per-model behaviour depends on capability gates baked into the request shape (see Beta header). The current gates target opus-4-6 / sonnet-4-6 for adaptive-thinking and effort; newer models (e.g. Opus 4.7) fall through to the conservative defaults until the gates are updated.
API Details
Endpoint: POST {base_url}/v1/messages?beta=true
Authentication & identity headers:
Authorization: Bearer <oauth_token>anthropic-version: 2023-06-01anthropic-beta: <comma-separated beta list>(computed per request, see below)x-app: cliUser-Agent: claude-cli/<version> (external, cli)X-Claude-Code-Session-Id: <uuid>(per-process)- Stainless SDK identification headers (
x-stainless-*)
Beta header
Composed dynamically from the model + thinking settings, mirroring Claude Code’s getAllModelBetas (utils/betas.ts). Order is significant; wire dumps from Claude Code show this exact ordering:
| Beta | When |
|---|---|
claude-code-20250219 | All models except Haiku family |
oauth-2025-04-20 | Always (subscription auth) |
adaptive-thinking-2026-01-28 | Thinking on AND model is opus-4-6 / sonnet-4-6 |
interleaved-thinking-2025-05-14 | Thinking on AND model is older Claude 4 (Sonnet 4.0, etc.) |
redact-thinking-2026-02-12 | Any modern Claude (4.x+); on by default, redact_thinking = false opts out |
context-management-2025-06-27 | Any modern Claude (4.x+) |
prompt-caching-scope-2026-01-05 | Always |
effort-2025-11-24 | opus-4-6 / sonnet-4-6 only |
System prompt
Sent as an array of three text blocks:
x-anthropic-billing-header: cc_version=<version>.<fingerprint>; cc_entrypoint=cli; cch=<xxHash64-attestation>;The fingerprint suffix is a 3-character hex hash derived from the first user message (SHA256(salt + msg[4] + msg[7] + msg[20] + version)[:3]); thecchtoken is xxHash64 of the entire serialized request body, computed and patched in just before send.You are Claude Code, Anthropic's official CLI for Claude.(fixed identity prefix).- Your own system prompt, which carries
cache_control: {type: "ephemeral", ttl: "1h", scope: "global"}.
Only block 3 is marked for caching, matching the captured Claude Code CLI wire shape (“boundary mode” in utils/api.ts:362-409); scope: "global" shares the cached prefix across sessions. Tools carry no cache_control (the rolling last-message breakpoint caches the tools+system prefix). Blocks 1 and 2 must come first so the cch=00000 placeholder is the first occurrence in the serialized JSON, which is what patch_request_body looks for when computing the attestation.
Other body fields
metadata.user_id: JSON-encoded{"device_id": "...", "account_uuid": "", "session_id": "..."}(device_idfrom the profile’sdevice_id;session_idis per-process).context_management.edits = [{type: "clear_thinking_20251015", keep: "all"}]: present when thinking is enabled on a context-management-capable model. Mirrors Claude Code’sapiMicrocompact.output_config.effort: present for effort-capable models, value from the profile’seffort.temperature: 1(only when thinking is disabled).max_tokens:64_000for adaptive-thinking models,max(thinking_budget * 2, 32_000)for legacy thinking models,32_000otherwise.
Cache control
The most recent message’s last content block, the last tool definition, and the user system prompt all carry cache_control: {type: "ephemeral", ttl: "1h"}. The 1h TTL matches Claude Code’s getCacheControl for OAuth subscribers (should1hCacheTTL in claude.ts:358-374). Mid-session permission toggles never invalidate this cache; see Permissions for the reasoning.
Streaming
Server-Sent Events with the same event taxonomy as claude-api: content_block_start, content_block_delta, content_block_stop, message_delta, message_stop. Reasoning streams as thinking_delta events; redacted thinking arrives as a single [redacted] block plus a signature.