Skip to content

auth

auth

Authentication workflows for AI coding agents.

Provides a data-driven registry of auth providers (AUTH_PROVIDERS) and a single entry point authenticate(project_id, provider) that runs the appropriate flow inside a temporary L2 CLI container.

The shared helper _run_auth_container handles the common lifecycle: check podman, load project, ensure host dir, cleanup old container, run.

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',), api_key_hint='') 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

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).

api_key_hint = '' class-attribute instance-attribute

Hint shown when prompting for an API key (URL to get one).

supports_oauth property

Whether this provider supports OAuth (container-based) auth.

supports_api_key property

Whether this provider supports direct API key entry.

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").

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>"}.

Source code in src/terok_agent/auth.py
def store_api_key(
    provider: str,
    api_key: str,
    credential_set: str = "default",
) -> None:
    """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>"}``.
    """
    from terok_sandbox import CredentialDB, SandboxConfig

    cfg = SandboxConfig()
    db = CredentialDB(cfg.proxy_db_path)
    try:
        db.store_credential(credential_set, provider, {"type": "api_key", "key": api_key})
        print(f"API key stored for {provider} (set: {credential_set})")
    finally:
        db.close()

authenticate(project_id, provider, *, mounts_dir, image)

Run the auth flow for provider against project_id.

Dispatches based on the provider's modes field:

  • api_key only: prompt for key, store directly (no container)
  • oauth only: launch container with vendor CLI
  • both: ask user to choose, then dispatch accordingly

Parameters:

Name Type Description Default
project_id str

Project identifier (for container naming).

required
provider str

Auth provider name (e.g. "claude").

required
mounts_dir Path

Base directory for shared config bind-mounts.

required
image str

Container image to use for the auth container.

required

Raises SystemExit if the provider name is unknown.

Source code in src/terok_agent/auth.py
def authenticate(
    project_id: str,
    provider: str,
    *,
    mounts_dir: Path,
    image: str,
) -> None:
    """Run the auth flow for *provider* against *project_id*.

    Dispatches based on the provider's ``modes`` field:

    - **api_key only**: prompt for key, store directly (no container)
    - **oauth only**: launch container with vendor CLI
    - **both**: ask user to choose, then dispatch accordingly

    Args:
        project_id: Project identifier (for container naming).
        provider: Auth provider name (e.g. ``"claude"``).
        mounts_dir: Base directory for shared config bind-mounts.
        image: Container image to use for the auth container.

    Raises ``SystemExit`` if the provider name is unknown.
    """
    info = AUTH_PROVIDERS.get(provider)
    if not info:
        available = ", ".join(AUTH_PROVIDERS)
        raise SystemExit(f"Unknown auth provider: {provider}. Available: {available}")

    if info.supports_oauth and info.supports_api_key:
        # Both modes — let the user choose
        print(f"Authenticate {info.label}:\n")
        print("  1. OAuth / interactive login (launches container)")
        print("  2. API key (paste key, no container needed)")
        print()
        choice = input("Choose [1/2]: ").strip()
        if choice == "2":
            key = _prompt_api_key(info)
            store_api_key(provider, key)
            return
        # choice == "1" or anything else → OAuth
        _run_auth_container(project_id, info, mounts_dir=mounts_dir, image=image)

    elif info.supports_api_key:
        # API key only — fast path, no container
        key = _prompt_api_key(info)
        store_api_key(provider, key)

    else:
        # OAuth only
        _run_auth_container(project_id, info, mounts_dir=mounts_dir, image=image)