Auth
auth
¶
Authenticates AI coding agents via OAuth or API key.
Two public entry points:
authenticate(project_id, provider, *, mounts_dir, image)— dispatches based on the provider'smodesfield: prompts for an API key (no container) or launches an auth container with the vendor CLI.store_api_key(provider, api_key)— stores an API key directly in the credential DB (non-interactive fast path for CI).
AUTH_PROVIDERS is a registry dict populated from the YAML roster at
package load time; authenticate looks up the provider by name and
delegates to the matching flow.
AUTH_PROVIDERS = {}
module-attribute
¶
All known auth providers (agents + tools), keyed by name. Loaded from resources/agents/*.yaml.
AuthProvider(name, label, host_dir_name, container_mount, command, banner_hint, extra_run_args=tuple(), modes=('api_key',), device_auth=False, api_key_hint='', post_capture_state=dict(), credential_provider='')
dataclass
¶
Describes how to authenticate one tool/agent.
name
instance-attribute
¶
Short key used in CLI and TUI dispatch (e.g. "codex").
label
instance-attribute
¶
Human-readable display name (e.g. "Codex").
host_dir_name
instance-attribute
¶
Single-segment directory name under mounts_dir() (e.g. "_codex-config").
container_mount
instance-attribute
¶
Mount point inside the container (e.g. "/home/dev/.codex").
command
instance-attribute
¶
Command to execute inside the container (OAuth mode only).
banner_hint
instance-attribute
¶
Provider-specific help text shown before the container runs.
extra_run_args = field(default_factory=tuple)
class-attribute
instance-attribute
¶
Additional podman run arguments (e.g. port forwarding).
modes = ('api_key',)
class-attribute
instance-attribute
¶
Supported auth modes: "oauth" (container), "api_key" (fast path).
device_auth = False
class-attribute
instance-attribute
¶
Whether the OAuth flow has a headless device-code variant.
When set, the auth prompt offers a device-code method alongside the normal
OAuth login: it runs <command> --device-auth with the normal flow's
port-forwarding (extra_run_args) dropped — the device-code flow polls a
remote endpoint and needs no localhost callback, so it works where the
operator can't complete the forwarded-port login.
api_key_hint = ''
class-attribute
instance-attribute
¶
Hint shown when prompting for an API key (URL to get one).
post_capture_state = field(default_factory=dict)
class-attribute
instance-attribute
¶
JSON state files to write after credential capture.
Maps filename → key-value dict to merge into a JSON file in the auth
mount directory. Example: {".claude.json": {"hasCompletedOnboarding": true}}
marks Claude Code onboarding as complete so the first-run wizard is skipped.
credential_provider = ''
class-attribute
instance-attribute
¶
Provider name the captured credential is stored under (e.g. "anthropic").
terok-executor auth claude authenticates Claude's default provider, so
the credential is keyed under anthropic — matching the vault route and
the v3-migrated DB. Populated by the roster loader from the agent's
provider.default binding; empty falls back to the entry's own name.
supports_oauth
property
¶
Whether this provider supports OAuth (container-based) auth.
supports_api_key
property
¶
Whether this provider supports direct API key entry.
supports_device_auth
property
¶
Whether this provider offers a headless device-code login variant.
__post_init__()
¶
Validate fields that become filesystem paths.
Source code in src/terok_executor/credentials/auth.py
AuthKeyConfig(label, key_url, env_var, config_path, printf_template, tool_name)
dataclass
¶
Describes how to prompt for and store an API key.
label
instance-attribute
¶
Human name shown in the prompt (e.g. "Claude").
key_url
instance-attribute
¶
URL where the user can obtain the key.
env_var
instance-attribute
¶
Name shown in the read -p prompt (e.g. "ANTHROPIC_API_KEY").
config_path
instance-attribute
¶
Destination inside the container (e.g. "~/.claude/config.json").
printf_template
instance-attribute
¶
printf format string (e.g. '{"api_key": "%s"}').
tool_name
instance-attribute
¶
Name shown in the success message (e.g. "claude").
Authenticator(provider)
dataclass
¶
Vendor-credential acquisition for a single agent.
Wraps the authenticate flow behind a stable class so callers
that orchestrate a multi-step setup (terok project init, the
standalone terok-executor auth command, the TUI auth flow)
talk to one named surface bound to self.provider.
The discovery counterparts
(list_authenticated_agents,
scan_leaked_credentials)
stay as module-level fns in their owning submodules — folding them
in here would create a tach cycle through terok_executor.acp
and terok_executor.credentials.vault_commands, which already
depend on this module transitively.
provider
instance-attribute
¶
Auth provider name (e.g. "claude").
run(project_id, *, mounts_dir, image=None, expose_token=False, oauth_enabled=True, credential_set='default', device_auth=False)
¶
Run the auth flow for self.provider; see module-level docs.
Mirrors the parameters of the underlying authenticate free
function — instance-bound self.provider replaces the old
positional provider arg. The device-code login is normally
offered as a method in that flow's prompt; pass device_auth to
skip the prompt and force it (the headless --device-auth path).
Source code in src/terok_executor/credentials/auth.py
prepare_oauth(project_id, *, mounts_dir, image, expose_token=False, credential_set='default', device_auth=False)
¶
Build an AuthSession without running it.
Frontends that own their own UI loop (e.g. the terok Textual TUI,
which wants to dispatch the OAuth container into a new terminal
tab or via tmux instead of inline) build the session here, run
session.argv however they like, then call session.capture()
on success. The CLI's blocking authenticate path is just
another such caller — see _run_auth_container.
With device_auth, the session runs the provider's headless
device-code login (see prepare_oauth_session).
Source code in src/terok_executor/credentials/auth.py
AuthSession(provider, project_id, container_name, argv, banner, auth_dir, mounts_dir, credential_set='default', expose_token=False, _tmpdir=None)
dataclass
¶
A prepared-but-not-run OAuth auth container session.
Built by Authenticator.prepare_oauth
(or the module-level prepare_oauth_session
helper). Hold-don't-call: the caller is responsible for running
argv (synchronously, in a new terminal tab, suspended TUI, etc.)
and calling capture() afterwards. Use as a context manager so
the temp dir and any dangling container are cleaned up on exit.
provider
instance-attribute
¶
Provider descriptor (label, banner hint, mount points).
project_id
instance-attribute
¶
Project scope for the banner; None for host-wide auth.
container_name
instance-attribute
¶
Podman container name (used for cleanup and -it log clarity).
argv
instance-attribute
¶
The podman run … command line — run this however you like.
banner
instance-attribute
¶
Banner text to display before launching argv.
auth_dir
instance-attribute
¶
Temp dir bind-mounted as the container's auth config target.
Lives until cleanup() (or __exit__). Credential extraction
in capture() reads from here, so don't remove it manually.
mounts_dir
instance-attribute
¶
Base directory for the shared post-capture mount (OAuth providers only).
credential_set = 'default'
class-attribute
instance-attribute
¶
Which credential set in the vault DB receives the captured token.
expose_token = False
class-attribute
instance-attribute
¶
When True, real credential files are copied into the shared mount (tier 3).
title
property
¶
Short human-readable title ("Authenticating Claude (host-wide)").
capture()
¶
Extract credentials from auth_dir, store them in the vault DB.
Call after argv exits successfully. Safe to call multiple
times (the underlying extractor is idempotent on a stable
credential file).
Source code in src/terok_executor/credentials/auth.py
cleanup()
¶
Release the temp dir and force-remove any lingering container.
Idempotent. __exit__ calls this automatically.
Source code in src/terok_executor/credentials/auth.py
__enter__()
¶
authenticate(project_id, provider, *, mounts_dir, image=None, expose_token=False, oauth_enabled=True, credential_set='default', device_auth=False)
¶
Run the auth flow for provider, optionally scoped to a project.
Offers every auth method the provider supports — OAuth (vendor CLI in a
container), the OAuth device-code variant (for providers that declare
device_auth), and a direct API key — as the effective mode set: what
the roster declares (modes:, device_auth) intersected with what the
caller permits via oauth_enabled. One method runs straight through; two or
more prompt the user to choose.
Pass device_auth to force the device-code variant non-interactively
(the headless --device-auth path): the menu is skipped and the
device-code login runs straight through. Raises SystemExit if the
provider has no device-code login or OAuth is gated off.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id
|
str | None
|
Project identifier used for container naming and the
banner line. Pass |
required |
provider
|
str
|
Auth provider name (e.g. |
required |
mounts_dir
|
Path
|
Base directory for shared config bind-mounts. |
required |
image
|
str | Callable[[], str] | None
|
Container image for the OAuth container. Either a tag
string (eager) or a zero-arg callable returning the tag
(lazy — invoked only when the user actually chooses the
OAuth path). |
None
|
expose_token
|
bool
|
When True, copy the real credential files into
the shared mount instead of writing a phantom marker. Used
by tier 3 ( |
False
|
oauth_enabled
|
bool
|
External gate for the OAuth path. |
True
|
credential_set
|
str
|
Storage namespace in the vault DB. Defaults to
|
'default'
|
Raises SystemExit if the provider name is unknown or no usable
auth mode remains after gating.
Source code in src/terok_executor/credentials/auth.py
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | |
credential_provider(name)
¶
Resolve an auth target (agent name) to the provider its credential is keyed under.
terok-executor auth claude authenticates Claude's default provider, so
the credential is stored under anthropic — the same key the vault route
and the v3-migrated DB use, so routed = stored & routes intersects at
runtime. Tools resolve the same way (gh → github). Names not in the
auth registry (harnesses with no credentials, or already a provider) pass
through unchanged.
Reads the auth registry rather than the roster so the credentials layer
stays below it — the resolved provider rides on each
AuthProvider, populated by
the loader.
Source code in src/terok_executor/credentials/auth.py
store_api_key(provider, api_key, credential_set='default')
¶
Store an API key directly in the credential DB (no container needed).
This is the non-interactive fast path for automated workflows and CI.
The key is stored as {"type": "api_key", "key": "<value>"} under the
resolved provider name (see credential_provider).
Source code in src/terok_executor/credentials/auth.py
prepare_oauth_session(provider, project_id, *, mounts_dir, image, expose_token=False, credential_set='default', device_auth=False)
¶
Build an AuthSession without running it.
Creates a fresh temp dir, computes the podman run argv, and
cleans up any leftover container of the same name (so re-auth
after a previous abort isn't blocked). The caller drives execution
and credential capture; see AuthSession.
The temp dir uses a clean slate so the vendor auth flow re-runs end to end — no stale config, no cached sessions.
With device_auth, the command gains --device-auth and the
port-forwarding extra_run_args are dropped: the device-code flow
polls a remote endpoint, so there is no localhost callback to forward.
Source code in src/terok_executor/credentials/auth.py
api_key_command(cfg)
¶
Build a bash command that prompts for an API key and writes it to a config file.