# Authentication **Status:** Implemented · **Code:** `Scripts/auth.js`, `Scripts/cli.js` The extension never implements an OAuth flow and never sees credentials. It drives Claude Code's own commands. > **Policy constraint.** Anthropic's Agent SDK terms state that third-party > developers may not offer claude.ai login in their products. Delegating to > `claude auth login` is the compliant path *and* the robust one — credentials > land where Claude Code expects them. Do not reimplement the PKCE flow here. ## Status `claude auth status --json` → ```json {"loggedIn":true,"authMethod":"claude.ai","apiProvider":"firstParty", "email":"…","orgId":"…","orgName":"…","subscriptionType":"pro"} ``` `describe(state)` renders the sidebar's one-liner ("you@example.com · Pro"). ## Sign-in `claude auth login [--claudeai | --console]` is spawned with piped stdio. The extension scans stdout/stderr for an authorization URL, opens it with `nova.openURL`, then prompts for the code and writes it to the child's stdin. If no URL appears within 20s the attempt is abandoned with a message pointing at the terminal. `signInViaTerminal()` is the fallback for SSO or device prompts: it writes a `sign-in-to-claude.command` script to global storage, `chmod +x`, and `open`s it so a real terminal runs `claude auth login`. ## API key alternative Stored with `nova.credentials` (service `unsupervised.claudenova`, account `ANTHROPIC_API_KEY`) and injected into the spawned process environment by `cli.environment()`, where it takes precedence over the signed-in account. ## Gotchas - `cli.environment()` reads the keychain on every spawn. Cheap, but it means keychain failures must be non-fatal — they are logged and ignored. - Nova's task environment can be sparse; `environment()` fills in a default `PATH` and `HOME` so the CLI can find its own tooling.