Expand description
OAuth 2.0 Authorization Code + PKCE flow for Anthropic (Claude Pro/Max).
Implements the same flow as Claude Code and Pi coding agent:
- Generate PKCE verifier + challenge
- Start localhost callback server
- Open browser to claude.ai/oauth/authorize
- Capture redirect with auth code
- Exchange code for access + refresh tokens
- Save to ~/.pi/agent/auth.json (shared with Pi)
Modules§
- account
- Account references for multi-account OAuth credentials.
- anthropic_
profile - Anthropic OAuth profile lookup: the seat identity behind a Claude credential.
- auth_
state synaps auth state: what one broker remembers about its accounts (each account’s cooldown, its last usage read and last token refresh exchange, and the last automatic selection), read from memory only.- auto_
selection - Automatic subscription choice and its secret-free explanation.
Eligibility remains in
quota_policy; config and the preview use that same policy so the CLI cannot promise a different account than the broker. - aws_
bedrock - Provider-local IAM Identity Center and Bedrock broker boundary. The transport trait is intentionally typed: it cannot sign arbitrary URLs or vend credentials.
- azure_
openai - Provider-local Azure OpenAI OAuth, catalog, and broker request contracts. No function in this module performs network I/O or returns credentials.
- broker
- The credential broker — the mandatory boundary between runtimes and
provider secrets (Checkpoint 1 decision,
docs/decisions/credential-broker-checkpoint-1.md). - broker_
token - Zero-config machine token for a loopback
synaps auth-broker(#147 C1). - cloud
- Shared, credential-free cloud provider contracts.
- cloud_
login - Provider-specific interactive cloud login protocols. Credentials remain persisted only through the broker-owned auth store.
- github_
copilot - GitHub Copilot OAuth (device authorization + broker-owned session mint).
- google_
gemini - Google Gemini (Code Assist) OAuth: authorization-code + PKCE.
- google_
vertex - Provider-local Google Vertex AI installed-app OAuth primitives.
- identity
- Provider-generic seat identity resolution.
- kimi_
code - Kimi Code OAuth (RFC 8628 device authorization; direct bearer, no mint).
- muse
- Meta Muse Code OAuth (RFC 8628 device authorization + Model API key mint).
- provider
- Typed OAuth provider identity, descriptors, registry validation, and dispatch.
- providers
- quota_
keeper - G6 — quota keeper: pure scheduler state machine, private persisted state and singleton/attempt locking.
- quota_
policy - G5 — pure capacity-selection policy for multi-account OAuth providers.
- static_
providers - Static-key provider connection metadata, owned by the credential broker.
- usage
- Read-only, normalized quota/usage snapshots for the four OAuth providers the multi-account broker manages: Claude (Anthropic), ChatGPT/Codex, Kimi Code and Grok (xAI).
- usage_
reads - Process-wide table of Anthropic/OAuth usage reads, one entry per account
slot, shared by every
LocalBrokerin the process (a daemon can hold several brokers, one per runtimeTokenCache).
Structs§
- Access
Token - An OAuth access token vended by the broker.
- Account
Failure - One account’s part in a failed selection.
- Account
Inventory - Listing of one provider’s stored accounts plus any sibling keys that look like accounts of this provider but fail validation (never loaded).
- Account
Label - Validated account label. Grammar:
^[a-z0-9][a-z0-9._-]{0,31}$; the wordsdefaultandautoare reserved and rejected. - Account
Metadata - Non-secret metadata stored beside a credential (
label,identity,addedAt). Kept separate fromOAuthCredentialsso refresh writes, which only carry token fields, never clobber it. - Account
Policy - Per-provider account selection. Built once from config (+ env overlay); never mutates the process environment or the active profile.
- Account
Summary - Non-secret listing row for one stored account. Never carries token
material;
account_id_prefixis at most 8 characters. - Anthropic
Profile - Non-secret identity of the Claude account behind an OAuth credential.
account_uuidis the seat identity used for duplicate detection. - Auth
File - Auth
State Query - Which accounts to report on, and whether to clear their state first.
- Auth
State Report - One broker’s in-memory account state.
- Auto
Selection Policy - AwsBedrock
Config - Azure
Open AiConfig - Broker
Client - HTTP client for a credential broker. Presents the machine’s own bearer token (NOT the provider credential) and receives a short-lived access token.
- Broker
Message - Broker
Token - An access token as returned by the broker’s
GET /token. - Broker
Tool - Callback
Result - Result from the OAuth callback.
- Callback
Server Handle - Credential
Ref - A fully addressed OAuth credential: provider + account slot.
- Google
Vertex Config - Invoke
Options - Invoke
Request - Local
Broker - In-process credential broker. This module is the ONLY place runtime-serving
code may read
auth.json,provider.<key>config values, or credential environment variables. - Login
Persist Outcome - Outcome of
save_credential_unless_duplicate. - Machine
Token - The machine token a client presents to a broker, with its provenance.
- OAuth
Credentials - OAuth
Provider Descriptor - OAuth
Provider Registry - Observation
Failure - A failed observation: its kind plus the HTTP status and
Retry-Afterthe provider sent, when there were any. Never token material or body bytes. - Pinned
Token - The selected/pinned pair a runtime works with for one attempt: the
credential the broker chose and the token vended for exactly that
credential. Account-specific headers (e.g. the Codex account id) must be
derived from
token, never from a second lookup. - PlanRow
- Provider
Status - Non-secret capability/status row for one provider.
- Proxy
Request - A typed, credential-free request the broker executes on the caller’s behalf against an OpenAI-compatible provider endpoint.
- Proxy
Response - Buffered (non-streaming) proxy result: upstream status + body text.
- Refresh
Failure - A refresh failure: its kind plus a log-safe message (our own texts, or provider errors that went through the provider’s sanitizer) and, when the token endpoint answered with a failure, its HTTP status. Never carries token material.
- Remote
Broker - Client for a remote
synaps auth-broker. Presents the machine’s own bearer token; receives access tokens (OAuth) and proxied responses (static-key providers). Never receives refresh tokens or raw keys. - Resolved
Seat - Identity of the seat an access token belongs to.
account_idis the provider’s FULL account id (the value stored asaccountIdand hashed bysuper::seat_fingerprint);identityis a display-only label such as an email. Neither is a secret. - Seat
Identity - Identity of the credential material currently stored in one slot. Scopes
per-slot caches and pairs a proven-capacity reading with the token vended
for it: the provider seat (via
seat_fingerprint) when the credential carries an account id — stable across token rotation — otherwise a digest of the refresh material, which changes on re-login and on rotation. An opaque digest: not reversible, never logged with token material. - Selection
Failure - A failed automatic selection: the top-level kind, every account’s part in it, and the earliest known reset among limited accounts.
- Selection
Plan - Static
Provider Spec - Connection/credential metadata for one static-key provider.
- Token
Cache - Thread-safe cache of broker access tokens. Cloneable handle over shared state. Holds ONLY short-lived access tokens, never a refresh token, never persisted to disk.
- Usage
Snapshot - Normalized, secret-free usage observation for one
(provider, account).
Enums§
- Account
- A concrete account slot for a provider.
- Account
Failure Kind - Why one account could not serve a request, as a stable snake_case kind: a failed observation (usage read, token refresh, credential store) or the policy verdict on a good one. Secret-free; safe for logs and users.
- Account
Selector - What a caller asks for when no explicit account is given.
- Auth
Identity - Credential mechanism used behind the broker boundary.
- Broker
Credential Strategy - How a runtime may obtain a usable credential from the broker.
- Broker
Error - Broker failures. Messages never contain credential values. Non-exhaustive: new failure kinds are added as brokers gain operations.
- Broker
Operation - Broker
Token Origin - How
load_or_create_broker_tokenobtained the token. - Callback
Outcome - Cloud
Provider Id - Credential
Kind - What kind of credential a provider uses. Never carries key material.
- Credential
Source - Where a client gets its provider credentials.
- Identity
Evidence - What the duplicate-identity guard could establish for a new login.
- Message
Role - OAuth
Provider Id - Provider
Id - General auth identity. Existing OAuth identity remains strongly typed.
- Proxy
Method - HTTP method subset the proxy protocol supports.
- Refresh
Failure Kind - Why a locked refresh produced no token, so callers can tell the user
the right thing: only
RefreshFailureKind::Credentialmeans the login itself is unusable (“runsynaps login”). - Seat
Resolution - Outcome of
resolve_seat. - Selection
Failure Kind - The one kind that explains a failed automatic selection.
- Static
KeyStatus - Non-secret display status for one static key (settings UI).
- Usage
Error - Usage failures.
Display/Serializenever include a token, a URL query, or any upstream body bytes.
Constants§
- ANTHROPIC_
PROFILE_ URL - Pinned Anthropic OAuth profile endpoint.
- AUTH_
STATE_ SCHEMA_ VERSION - Version of
AuthStateReport’s JSON shape (synaps auth state --json). - AUTO_
ACCOUNT_ NAME - Reserved selector word for opt-in automatic selection (G5).
- DEFAULT_
ACCOUNT_ NAME - Reserved word for the bare provider slot. Never a label.
- DEFAULT_
MARGIN_ MS - Default refetch margin: 5 minutes (mirrors
is_token_expired). - LOCAL_
BROKER_ TOKEN_ FILE - File name of the auto-generated loopback broker token.
- LOCAL_
PROVIDER_ KEY - The local OpenAI-compatible endpoint pseudo-provider (Ollama, LM Studio…). Its endpoint URL is non-secret user configuration; its optional key is still broker-owned.
- MAX_
PROXY_ REQUEST_ BYTES - Maximum serialized size of a proxy request body.
- MAX_
PROXY_ RESPONSE_ BYTES - Maximum buffered (non-streaming) response body size.
- MAX_
UPSTREAM_ ERROR_ BYTES - Historical cap for upstream error-body snippets. Upstream/broker error
bodies are no longer read at all (spec §5.1: they may echo the request);
the constant remains only because it is re-exported from
auth::mod. - PROXY_
REQUEST_ TIMEOUT - Total time budget for a buffered (non-streaming) broker-executed request.
Traits§
- Credential
Broker - The typed credential broker protocol. One implementation runs in-process
(
LocalBroker) so normal local use needs no daemon; the other talks to a remotesynaps auth-brokerover authenticated HTTP(S) (RemoteBroker). - Token
Fetcher - “Get a fresh access token from somewhere.” Abstracted so the cache/resolve
logic is unit-testable without real HTTP. The real impl is
BrokerClient.
Functions§
- account_
config_ key - Config key carrying the selected account for a provider.
- account_
env_ var - Environment variable that selects the account for a provider:
SYNAPS_ACCOUNT_<PROVIDER>with-→_, upper-cased. - any_
oauth_ credential_ present - True if auth.json holds at least one OAuth credential of ANY provider or account. Used for broker startup/health so non-Anthropic-only installations work.
- auth_
file_ path - Get the path to auth.json (~/.synaps-cli/auth.json).
- broker_
from_ source - remote transport. There is no third option — and no direct-read fallback.
- build_
auth_ url - Build the full authorize URL for the browser.
- ensure_
fresh_ credential - Ensure one addressed credential (provider + account) has a fresh token.
- ensure_
fresh_ provider_ token - Ensure an OAuth provider (including Anthropic) has a fresh token in its
default account slot. Equivalent to
ensure_fresh_credentialwithCredentialRef::default_for. - ensure_
fresh_ token - Acquire the Anthropic refresh gate, check token freshness, refresh if needed, and persist the result atomically. Returns the current (possibly refreshed) credentials.
- exchange_
code_ for_ tokens - Exchange an authorization code for access + refresh tokens.
- extract_
codex_ account_ id - extract_
codex_ email - Display-only identity (email claim) carried by a Codex access token, if present. Never a secret; used to label accounts in listings.
- fetch_
anthropic_ profile GETthe profile foraccess_tokenand parse it.endpoint_overrideis a loopback-only test seam. The caller’sclientshould follow no redirects (seesuper::identity::identity_http_client); a 3xx is an error here regardless. Errors never contain the token or upstream bytes.- fetch_
usage - Read-only usage fetch for one
(provider, account)using the caller’s already-resolved access token. See the module docs for the guarantees. - find_
duplicate_ identity - Duplicate-identity guard for login: returns the account (of the same
provider, other than
except) that already storesaccount_id. - generate_
code_ challenge - Compute S256 code challenge from verifier.
- generate_
code_ verifier - Generate a cryptographically random code verifier (43-128 chars, base64url).
- generate_
state - Generate a random state parameter.
- global_
broker - The process-wide broker. Defaults to the in-process
LocalBrokerso normal local use never requires a separately launched daemon. - global_
broker_ install_ count - How many times
set_global_brokerhas run in this process. - identity_
http_ client - HTTP client with the policy identity lookups (and the token refresh that may precede them) require: no redirects, bounded connect/total timeouts.
- is_
expired_ with_ margin - True if
expires_msis already past, or withinmargin_msof now. - is_
loopback_ endpoint - True when
endpointis an http(s) URL whose host is loopback (localhost,127.0.0.0/8,::1). - is_
token_ expired - Check if the current token is expired.
- list_
accounts - Enumerate stored OAuth accounts for
provider(non-secret rows;selectedis leftfalsefor the caller to annotate). - list_
accounts_ detailed - Enumerate with malformed-key diagnostics (for
auth list). - list_
all_ accounts - Enumerate stored OAuth accounts for every provider.
- load_
auth - Load credentials from auth.json.
- load_
cloud_ state - Load an opaque broker-owned cloud provider state object.
- load_
credential - Load the credential stored in one account slot.
- load_
or_ create_ broker_ token - Broker side: read the token at
path, or create it when absent. - load_
provider_ auth - Load one provider’s OAuth credential from auth.json.
- load_
static_ key - Load one provider’s broker-owned static API key from auth.json.
- local_
auth_ state synaps auth statefor the local brokercacheholds for the current credential store and config (the one requests use) or, when no request has built one yet, the account list with nothing recorded.live: the caller is the process that serves requests (the daemon). No network request, no refresh;query.clearnever writes the store.- local_
broker_ token_ path <base_dir>/auth-broker.token.- login
- Run the full OAuth login flow into the default Anthropic slot.
- login_
github_ copilot - Production login entry (real network + system browser + auth.json).
- login_
into - Run the full OAuth login flow. With
Some(key)the credential is persisted ONLY into that slot (anthropicoranthropic@<label>); withNoneit is returned unsaved so the caller can run pre-persistence checks. - login_
kimi_ code - Production login entry (real network + system browser + auth.json).
- login_
muse - Production login entry (real network + system browser + auth.json).
- login_
openai_ codex - login_
xai - open_
browser - Open a URL in the default browser.
- parse_
anthropic_ profile - Pure parser for the profile body. Fails closed when
account.uuidis missing, empty, non-string or over-long; every other field is optional and unknown/null fields are ignored. - preflight_
cloud_ capability - Build the right broker for a credential source. Local sources get the in-process broker (no daemon needed); remote sources get the authenticated Pre-flight capability check for a cloud route (spec §5.5). Pure function: callers MUST run it before constructing a broker, looking up credentials, or opening any connection. The invoke-time guard inside the broker remains in place as defense in depth.
- read_
local_ broker_ token - Client side: the local broker token, if the file exists and is non-empty.
- refresh_
token - Refresh an expired OAuth token. Failures are typed at the source: no
response or an unusable success body is transient, a status is
classified by [
status_kind]. - remove_
credential - Remove one account slot. Returns
trueif a key was removed. Never leaves a partial file and never touches any other key. A corrupt file is an error (nothing is reset on a removal path). - resolve_
access_ token - Provider-aware token resolution honoring the credential source — kept as a
compatibility adapter for CLI callers (
synaps status). Delegates to the typed credential broker: the local in-process broker or the authenticated remote transport. Vends the access token only. - resolve_
remote - Resolve a provider token via cache-or-fetch, returning the full
BrokerToken(access + expiry). The runtime needs the expiry to drive its in-memory refresh trigger. NEVER touches a refresh token orauth.json. - resolve_
remote_ token - Like
resolve_remotebut returns only the access token string. - resolve_
seat - Resolve the seat behind
access_tokenforprovider.endpoint_overrideis a loopback-only test seam for the network-backed providers. - save_
account_ metadata - Merge non-secret metadata into an account slot (which must already exist).
- save_
auth - Save credentials to auth.json.
- save_
cloud_ state - Atomically persist opaque cloud state while preserving every unrelated field.
- save_
credential - Persist a credential into exactly one account slot. Other slots (including
the provider’s default slot) and any non-secret metadata already stored in
this slot are preserved. A corrupt store is an error — the account path
never resets the file (that would wipe every other slot); the legacy
single-credential
save_provider_authresets only an empty file. - save_
credential_ unless_ duplicate - Login persistence: duplicate scan and write happen inside ONE locked
read-modify-write of auth.json, so two concurrent logins (or a login
racing a remove/re-login) can never create two slots owning the same
seat. A duplicate is another slot of the same provider with the same
non-empty
accountId, or with an identical refresh token. - save_
provider_ auth - Save one provider credential while preserving other auth.json entries.
- save_
static_ key - Persist a broker-owned static API key while preserving every other auth.json entry and any provider metadata.
- seat_
fingerprint - Stable, opaque seat fingerprint: hex SHA-256 over a domain tag, the
provider id and the provider’s FULL account id (e.g. the Codex
chatgpt_account_idclaim). Deterministic across processes and hosts, so a consumer holding a vended token can derive the same value from that token’s claim and compare it withAccountSummary::seat_fingerprintbefore spending on the listed seat. Never derived from token material. - set_
global_ broker - Install the process-wide broker (called once from runtime configuration).
Every call is counted (
global_broker_install_count) and, whenSYNAPS_MEM_TRACE=1, logged — the daemon-mode S7 gate asserts the count stays at 1 across subagent spawns. - set_
slot_ identity - Record the provider seat identity on an EXISTING OAuth slot: sets
accountId(the full provider account id) and, when given, the displayidentity. Used by theauth identifybackfill for slots whose login predates identity acquisition (Anthropic tokens are opaque; the seat comes from the profile endpoint after the fact). - start_
callback_ server - start_
callback_ server_ at - static_
provider - Look up a static provider spec by key.
- supports_
seat_ identity - True when
resolve_seatcan, in principle, returnSeatResolution::Resolvedforprovider. Used by listings to point at slots whose identity is still unverified. - unauthorized_
hint - Actionable text for a broker 401 (client side).
Type Aliases§
- Proxy
Byte Stream - Streaming proxy result: raw upstream bytes (SSE), post-authorization.