ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, or
AZURE_OPENAI_API_KEY plus AZURE_OPENAI_ENDPOINT) — set them and
rkat run works. The powerful path is realm-scoped bindings:
declare a realm in your config, register credentials via rkat auth login or the REST/RPC surfaces, and pass --auth-binding <realm>:<binding> to scope a session or mob member to that specific
binding.
rkat auth login provisions the reserved global realm in the home-rooted doc
at ~/.rkat/config.toml. Because global is the universal tail of every realm
chain, a single sign-in is inherited by every workspace realm (credential reads
inherit down the chain). For a binding owned by a specific realm such as
prod:openai, manage that realm’s config entries directly; credential writes
are strict-owner and land only in the realm that defines the binding. See
Realm inheritance.What this guide is for
Use this guide when you need more than the env-var fast path:- explicit realm-scoped bindings
- OAuth or cloud-IAM-backed auth
- hot-swapping provider identity
- per-mob-member credential overrides
ProviderRuntimeRegistry. There’s no
hidden magic path: the env fallback is a synthesized realm with
CredentialSourceSpec::Env, resolved by the same code that handles
your configured realms.
The fast path: env vars
env_default) with a binding that reads the key via
CredentialSourceSpec::Env, then resolves normally. RKAT_*-prefixed
env vars (e.g., RKAT_ANTHROPIC_API_KEY) take precedence over the
provider-native names.
If both public OpenAI and unprefixed Azure OpenAI env vars are present, the
public OpenAI env default wins. Use
RKAT_AZURE_OPENAI_API_KEY plus
RKAT_AZURE_OPENAI_ENDPOINT, or an explicit realm binding, to make Azure
OpenAI the env default in that case.
The powerful path: realms + bindings
A realm is a named collection of backend profiles, auth profiles, and provider bindings. It lets you:- Run multiple sessions against different accounts or tenants
- Mix OAuth (Claude.ai Pro/Max), api_key (keyed by CI), and cloud IAM (Bedrock/Vertex/Foundry) in one process
- Hot-swap a session’s active binding mid-conversation
- Give different mob members different credentials
Realm shape
openai) with an Azure-specific
backend/auth pair:
Log in
rkat auth login persists credentials and the matching [realm.global]
binding section into the home-rooted global realm doc (~/.rkat/config.toml),
so the sign-in is inherited by every workspace realm via the chain tail. To use
a binding owned by another realm (for example prod:openai), declare that
binding in the owning realm’s config; credential writes are strict-owner and
land only in the realm that defines the binding.
Use the binding
Subcommands
1
Login and profile management
2
Status and refresh
rkat auth refresh is a no-op for api_key / azure_api_key / static_bearer
auth methods (nothing to refresh). For OAuth-backed methods it
exchanges the persisted refresh token for a fresh access token and
writes the new bundle back to the TokenStore.3
Delete
Release auth smoke
make e2e-auth is the CI-safe auth smoke lane. It drives Meerkat’s
browser OAuth plumbing against a local OAuth fixture, verifies token-store
and AuthMachine lifecycle behavior across login, status, refresh, restart,
resolve, and logout, and skips optional live-provider canaries when their
seeded credentials are absent.
Real third-party browser login pages remain a manual pre-release check.
Do not automate provider-hosted OpenAI, Anthropic, or Google login pages in
CI; those pages are intentionally subject to MFA, CAPTCHA, account policy,
and provider UI changes.
Manual browser-login release checklist:
- Start login for the target provider.
- Confirm the system browser opens the provider-hosted login or consent page.
- Complete the callback and confirm Meerkat reports the login complete.
- Check auth status and confirm the target binding is
valid. - Run one tiny call through that binding.
- Logout and confirm auth status is cleared and the credential is gone.
Auth methods
Each provider’s runtime accepts a matrix of(backend_kind, auth_method) pairs. The table below summarizes what’s wired today.
External commands (
CredentialSourceSpec::Command) and file
descriptors (CredentialSourceSpec::FileDescriptor) let host
applications inject tokens without going through OAuth.
Credential sources
Thesource field on an auth profile declares where credentials
come from.
FileDescriptor is a host-integration seam rather than a plain standalone resolver path. It requires a host-scoped reader/injection path, so treat it as an advanced embedding surface rather than a generic CLI config trick.Hot-swap mid-session
When a session is created with--auth-binding prod:default, its
persisted SessionMetadata.auth_binding carries that binding through
resume and hot-swap. Changing the model/provider mid-turn via the RPC
turn/start override keeps the binding by default; pass an explicit
auth_binding on the turn request to scope the swap to a different
realm or binding.
ProviderRuntimeRegistry::resolve with the new
binding — no env-default fallback, no cross-realm credential bleed.
Per-mob-member override
Mob members default to env-default / config-realm fallback credentials. Passauth_binding on the host-side mob spawn surface to scope a member to a
specific binding:
auth_binding object only; the colon-joined realm:binding[:profile]
form is a CLI input convenience and is converted before it crosses the
wire boundary.
Native desktop hosts
Native applications should useHostAuthService for the complete interactive
transaction instead of recreating the CLI or RPC flow. The service owns strict
binding-owner resolution, PKCE and one-time state, exchange, coordinated
TokenStore persistence, AuthMachine lifecycle publication, rollback, status,
and logout. The application owns only its loopback listener, browser launch,
and UI.
Open one persistence capability and share that exact capability between
AgentFactory and HostAuthService:
MeerkatMachine alive for as long as the factory and auth service;
the snippet returns it in Arc, while a real host normally stores all three in
one application state object. A TokenStore open
failure is returned as a fault and is never collapsed into
interactive_login_required.
Managed-store resolution also requires per-session AuthMachine bindings. Do
not use the factory’s standalone build mode for a runtime-backed desktop
session:
native-keyring feature and
replace default_auto() with default_keyring_auto(). That profile preserves
an existing CLI file credential as the per-key authority, but a brand-new key
is written to the OS keyring. Use the same keyring-aware backend in every
process that must see desktop-first credentials; the stock CLI intentionally
uses the file profile to avoid surprise OS keychain prompts.
The browser flow is split for native UI:
- Bind the loopback listener and choose its redirect URI.
- Call
login_start(config, target, redirect_uri), then open the returnedauthorize_url. - Pass the callback’s
stateandcodetologin_complete. - Use
statusandlogoutfor secret-free UI projections and sign-out.
Refresh coordination
Refresh semantics are owned by theAuthMachine DSL (one instance
per <realm>:<binding>). On resolve, the runtime:
- Checks
expires_at. If present and within the refresh window (AUTH_LEASE_TTL_REFRESH_WINDOW_SECS, 60 seconds before expiry), marks the leaseExpiringvia the DSL. - Under
Expiring, the next resolve triggersBeginRefresh. In-process dedup ensures only one refresh HTTP call per binding even under concurrent resolves; cross-process dedup via filesystem lockfile whenrefresh-file-lockis enabled. - On successful refresh, fires
CompleteRefreshand updatesexpires_at. On failure,RefreshFailedTransient(retry) orRefreshFailedPermanent(routes toReauthRequired+ emits an[AUTH_REAUTH_REQUIRED]system notice on the session).
specs/machines/auth/.
Audit logging
Every accepted lifecycle transition emits a structured tracing event:target = "meerkat::auth::audit"- Fields:
binding_key,action,from_phase,to_phase
create_profile, delete_profile, login_oauth_complete,
login_device_complete, logout. Filter any tracing::Subscriber
on the meerkat::auth::audit target to build a persistent audit log.
Feature flags
Themeerkat-providers crate gates optional auth methods behind
features so you only pay for what you use:
The
rkat CLI enables anthropic, openai, gemini, and oauth
by default; add cloud-specific features at compile time for
Bedrock/Vertex/Foundry.
See also
- Hooks — observe auth events or gate turns on credential state
- Mobs — per-member
auth_bindingoverrides - Machine Authority — rationale behind single-owner runtime state
