Skip to content

feat(auth): user-selectable auth mode (subscription vs api_key)#109

Merged
George-iam merged 1 commit intomainfrom
feat/auth-mode-selection-20260416
Apr 17, 2026
Merged

feat(auth): user-selectable auth mode (subscription vs api_key)#109
George-iam merged 1 commit intomainfrom
feat/auth-mode-selection-20260416

Conversation

@George-iam
Copy link
Copy Markdown
Contributor

Summary

  • Fixes silent fallback to deterministic setup when Claude Code subprocess picks up an empty-balance ANTHROPIC_API_KEY and ignores the user's active subscription (observed on macOS, produces Credit balance is too low / 401 authentication_error even though claude itself is logged in).
  • Detects both auth options (API key + subscription), lets the user pick once, persists the choice in ~/.config/axme-code/auth.yaml, and deletes ANTHROPIC_API_KEY from the subprocess env when mode is subscription (empty string is not enough — Claude Code treats that as "set").
  • Adds axme-code auth subcommand for re-detecting and re-choosing at any time; non-interactive variants auth status and auth use <mode> for scripts. D-132 records the storage + fallback contract.

User-facing changes

  • First axme-code setup prompts once (TTY-only) with a detection block showing each option and where we found it (env var with masked tail; macOS Keychain or ~/.claude/.credentials.json). Non-TTY setup silently uses the heuristic — no silently-persisted guess.
  • axme-code auth — interactive re-detection and re-choice.
  • axme-code auth status — show current mode + detected options.
  • axme-code auth use subscription|api_key — non-interactive override.

Implementation notes

  • src/utils/auth-detect.ts — pure detection, no API probe. Keychain check runs security find-generic-password with stdio: ignore so we never reveal the secret.
  • src/utils/auth-config.ts — lazy path resolution via homedir() per call so tests can swap $HOME without module-cache busting.
  • src/utils/auth-prompt.ts — readline-based prompt, split out so auth-config stays dependency-free (scanner/auditor subprocesses can import it without pulling in stdio).
  • buildAgentEnv() in agent-options.ts is now the single source of the env we pass to every Claude Code subprocess. session-auditor.ts and memory-extractor.ts switched to use it — previously each built its own env object and only the scanner path would have benefited from the auth mode fix.

Test plan

  • npm run lint clean
  • npm test — 503/503 pass, including new auth-detect and auth-config suites
  • npm run build clean
  • Smoke test: axme-code auth status on this dev box detects ~/.claude/.credentials.json, auth use subscription writes the yaml correctly, auth status reads it back
  • Manual: run axme-code setup --force on a fresh project in subscription mode with ANTHROPIC_API_KEY still set in env, verify scanners succeed (no "Credit balance" / 401)
  • Manual: run axme-code setup --force in a non-TTY context (piped), verify no prompt + no silently-persisted auth.yaml
  • Manual on macOS: verify Keychain detection branch finds the "Claude Code" service

🤖 Generated with Claude Code

Adds detection, persistent choice, and runtime enforcement of the
credential Claude Code subprocesses use for LLM scanner/auditor work.
Fixes "Credit balance is too low" and 401 authentication_error when
users have both an empty-balance ANTHROPIC_API_KEY lingering in shell
rc and an active Claude Code subscription — Claude Code prefers the
env var over OAuth, so axme-code now deletes it from the spawn env
when the user chose subscription mode.

- detectAuthOptions reports API key (masked) + subscription (macOS
  Keychain or ~/.claude/.credentials.json). No live API probe.
- User-level config at ~/.config/axme-code/auth.yaml (per machine,
  not per project — D-132).
- axme-code setup prompts once on first interactive run; stores
  choice. Non-TTY contexts skip prompt, fall back to heuristic
  without persisting.
- New subcommands: axme-code auth / auth status / auth use <mode>
  for re-detection and non-interactive override.
- buildAgentEnv() in agent-options.ts strips ANTHROPIC_API_KEY when
  mode=subscription; session-auditor and memory-extractor switched
  to share the same helper so auth behavior is consistent across
  every Claude Code subprocess we spawn.
- Tests: auth-detect (env handling, masking), auth-config (save/load
  roundtrip, corrupt YAML, unknown mode, HOME-based path).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
#!axme pr=none repo=AxmeAI/axme-code
@George-iam George-iam merged commit 0917efd into main Apr 17, 2026
George-iam added a commit that referenced this pull request Apr 17, 2026
Patch release with auth-mode selection (PR #109) and findClaudePath
fallback (PR #110, B-009) + dependabot patches.

What's new since v0.2.8:
- User-selectable auth mode: setup detects subscription + API key,
  prompts choice, persists in ~/.config/axme-code/auth.yaml. When
  subscription chosen, ANTHROPIC_API_KEY removed from subprocess env.
  New commands: axme-code auth, auth status, auth use <mode>.
- findClaudePath resolver: 5-step lookup (env vars, which, standard
  paths, nvm glob) so users without global claude in PATH don't hit
  the fileURLToPath crash.
- Dep patches: hono 4.12.14, protobufjs 7.5.5 (lockfile only).

Files bumped: package.json, .claude-plugin/plugin.json,
templates/plugin-README.md. CHANGELOG entry added.

Verified: 511/511 tests pass, tsc clean, npm run build clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant