# Credential System v2 (API + OAuth/token) — Implementation Checklist > **Archived (2026-02-18):** Historical implementation checklist. Canonical status is tracked in `docs/plans/state.json`; unchecked boxes here are not active backlog unless explicitly re-opened. **Date:** 2026-02-15 **Parent roadmap:** `docs/plans/2026-02-15-openclaw-gap-roadmap.md` **Goal:** Close the gap item "OAuth subscription auth" by supporting **both** API-key credentials and OAuth/token-based credentials (provider-specific) with consistent UX, per-tier control, and deterministic resolution. ## Scope Summary - Add `auth_mode` **per tier** (default/fast/complex/local and any `local_providers` entries). - Keep backward compatibility with existing `use_oauth` behavior. - Add stored credential support where it currently doesn't exist: - OpenAI: stored API key (OAuth already exists) - Anthropic: stored auth token (API key already exists) - Improve doctor output to surface which auth sources are present (without revealing secrets). Non-goals (explicitly out of scope for this checklist): - Inventing an Anthropic OAuth device flow. - Building new provider integrations (Vercel/MiniMax/etc.). ## Current Baseline (important constraints) - OpenAI OAuth uses the ChatGPT/Codex backend endpoint (SSE) and currently **does not support tools** on that path. - Source: `src/models/openai.ts` - Anthropic supports `apiKey` and `authToken` in `AnthropicClientConfig`. - Source: `src/models/anthropic.ts` - Stored credentials live at `~/.config/flynn/auth.json`. - Source: `src/auth/openai.ts`, `src/auth/anthropic.ts` ## Design Decisions ### 1) New config field: `auth_mode` Add `auth_mode` to the per-tier model config: - `auto` (default) - `api_key` - `oauth` `oauth` is interpreted as "OAuth/token mode" (provider-specific). For Anthropic, that means `auth_token`. ### 2) Backward compatibility: `use_oauth` Preserve `use_oauth` as a compatibility alias. Recommended rule: - If `auth_mode` is set: it wins. - Else if `use_oauth: true`: treat as `auth_mode: oauth`. ### 3) Credential resolution order For each provider, resolve the required credential type by trying: 1) config (`api_key` / `auth_token`) 2) env var 3) auth store (`~/.config/flynn/auth.json`) `auth_mode` controls which credential type is required. ## PR Breakdown (atomic, test-backed) ### PR 1 — Schema + docs: per-tier `auth_mode` Checklist: - [ ] Add `auth_mode` to `modelConfigBaseSchema` in `src/config/schema.ts`. - [ ] Update `src/config/schema.test.ts` to cover defaults + validation. - [ ] Update `README.md` config examples (brief mention). - [ ] Update `config/default.yaml` comment/help text (brief mention). Acceptance: - Config parses with no changes (defaults preserved). - Setting `auth_mode: oauth` or `auth_mode: api_key` validates. Tests: - `pnpm test:run src/config/schema.test.ts` --- ### PR 2 — OpenAI auth store: add API-key storage Goal: allow OpenAI to run without `api_key` in YAML. Checklist: - [ ] Extend `src/auth/openai.ts` `AuthStore` shape to allow `openai.api_key` alongside existing OAuth info. - [ ] Add functions: - [ ] `loadStoredOpenAIApiKey()` - [ ] `storeOpenAIApiKey(key)` - [ ] `clearOpenAIApiKey()` - [ ] `getOpenAIApiKey()` (env override + store) - [ ] Keep existing OAuth store code working unchanged. - [ ] Add/extend tests for new store functions. Files: - `src/auth/openai.ts` - `src/auth/openai.test.ts` (or add if missing) Acceptance: - Stored OpenAI API key is written to `~/.config/flynn/auth.json` with `0600` permissions. - OAuth entry remains backward compatible. Tests: - `pnpm test:run src/auth/openai.test.ts` --- ### PR 3 — Anthropic auth store: add auth-token storage Goal: allow `auth_token` to be stored and selected with `auth_mode: oauth`. Checklist: - [ ] Extend `src/auth/anthropic.ts` auth store shape to include `auth_token`. - [ ] Add functions: - [ ] `loadStoredAnthropicAuthToken()` - [ ] `storeAnthropicAuthToken(token)` - [ ] `clearAnthropicAuthToken()` - [ ] `getAnthropicAuthToken()` - [ ] Extend `src/auth/anthropic.test.ts`. Files: - `src/auth/anthropic.ts` - `src/auth/anthropic.test.ts` Acceptance: - `auth_token` can be stored and resolved without being present in YAML. Tests: - `pnpm test:run src/auth/anthropic.test.ts` --- ### PR 4 — CLI commands for managing new stored credentials Checklist: - [ ] Add `flynn openai-key` command (store API key in auth.json). - [ ] Extend `flynn anthropic-auth` to support storing either API key or auth token: - [ ] recommended: `flynn anthropic-auth --token` OR `flynn anthropic-token` - [ ] Update `src/cli/index.ts` registration. Files: - `src/cli/openai-key.ts` (new) - `src/cli/anthropic-auth.ts` (modify) - `src/cli/index.ts` Acceptance: - CLI can store credentials without printing them. - Re-running commands detects existing stored credentials and exits cleanly. Tests: - Add targeted unit tests if the CLI layer has existing patterns; otherwise validate via integration tests where feasible. --- ### PR 5 — TUI `/login` UX: OpenAI choice (OAuth vs API key) + Anthropic token Checklist: - [ ] Update `/login openai` in `src/frontends/tui/minimal.ts`: - [ ] Present a simple prompt: "1) OAuth device flow 2) Paste API key" - [ ] Store selected credential via auth store - [ ] Add `/login anthropic` in `src/frontends/tui/minimal.ts`: - [ ] "1) Paste API key 2) Paste auth token" - [ ] Keep existing `/login github` and `/login zai` behavior intact. Files: - `src/frontends/tui/minimal.ts` - `src/frontends/tui/commands.ts` (if command parsing needs to accept new provider) Acceptance: - TUI can store OpenAI API key or OAuth token. - TUI can store Anthropic API key or auth token. Tests: - Add or extend minimal TUI tests as needed (existing suite patterns exist for model switching). --- ### PR 6 — Model factory: enforce `auth_mode` per tier This is the core runtime change. Checklist: - [ ] Update `src/daemon/models.ts`: - [ ] Read `cfg.auth_mode` (or inferred from `use_oauth`) per tier. - [ ] For OpenAI: - [ ] `auth_mode=oauth`: configure `OpenAIClient({ useOAuth: true })` and verify OAuth tokens exist. - [ ] `auth_mode=api_key`: configure `OpenAIClient({ apiKey: resolvedKey })`. - [ ] For Anthropic: - [ ] `auth_mode=oauth`: require auth token (config/env/store). - [ ] `auth_mode=api_key`: require API key (config/env/store). - [ ] For other providers: - [ ] define behavior explicitly (likely `api_key` only unless provider already supports token-style auth). - [ ] Ensure error messages name the expected auth type and remediation. Files: - `src/daemon/models.ts` - potentially `src/models/openai.ts` (if you decide to unify API key vs OAuth selection naming) Tests: - `src/daemon/clientFactory.test.ts` - [ ] auth_mode precedence over use_oauth - [ ] auto -> api key path - [ ] oauth -> token path - [ ] correct failures when missing Acceptance: - Selecting `auth_mode` changes runtime behavior deterministically. --- ### PR 7 — Doctor: report auth source availability Checklist: - [ ] Extend `checkModelConnectivity` in `src/cli/doctor.ts` to reflect `auth_mode`: - [ ] If `auth_mode=api_key`, warn/fail when API key is absent from config/env/store. - [ ] If `auth_mode=oauth`, warn/fail when OAuth/token is absent. - [ ] If `auth_mode=auto`, keep current behavior but improve messaging. - [ ] Add tests in `src/cli/doctor.test.ts`. Acceptance: - Doctor output tells user what to do next (command name + env var) without exposing secrets. ## Final Integration Checks - [ ] `pnpm typecheck` - [ ] `pnpm test:run` - [ ] Update `docs/plans/state.json` entry for this checklist once implemented (status, summary, test status).