# QA.army agent authentication This is the public, agent-executable authentication contract for QA.army. Use the reference CLI because it keeps the claim token, WorkOS assertion, rotating refresh token, and access token out of command arguments, terminal output, files, and chat. ## Requirements - Node.js 22 or newer. - A native operating-system credential store: macOS Keychain, freedesktop Secret Service plus xdg-desktop-portal on Linux, or Windows Credential Manager. - The QA.army user's login email. If it cannot be discovered safely, ask for it before continuing. Download and verify the reviewed reference package from the immutable public QA.army artifact URL before installing it. macOS: ```sh archive_dir="$(mktemp -d)" archive="$archive_dir/qa-army-cli-0.2.0.tgz" curl -fLso "$archive" https://qa.army/downloads/qa-army-cli-0.2.0.tgz printf '%s %s\n' 2ec868577e208fa21f78ddc7512128c908a9c8799994b411f67f168a2c5a2c77 "$archive" | shasum -a 256 -c - npm install --global "$archive" rm -f "$archive" rmdir "$archive_dir" ``` Linux: ```sh archive_dir="$(mktemp -d)" archive="$archive_dir/qa-army-cli-0.2.0.tgz" curl -fLso "$archive" https://qa.army/downloads/qa-army-cli-0.2.0.tgz printf '%s %s\n' 2ec868577e208fa21f78ddc7512128c908a9c8799994b411f67f168a2c5a2c77 "$archive" | sha256sum -c - npm install --global "$archive" rm -f "$archive" rmdir "$archive_dir" ``` Windows PowerShell: ```powershell $archive = Join-Path ([IO.Path]::GetTempPath()) "qa-army-cli-0.2.0.tgz" Invoke-WebRequest "https://qa.army/downloads/qa-army-cli-0.2.0.tgz" -OutFile $archive $expected = "2ec868577e208fa21f78ddc7512128c908a9c8799994b411f67f168a2c5a2c77" if ((Get-FileHash $archive -Algorithm SHA256).Hash.ToLowerInvariant() -ne $expected) { Remove-Item $archive; throw "QA.army CLI archive checksum mismatch" } npm install --global $archive Remove-Item $archive ``` The same SHA-256 is returned in the public artifact's `X-Content-SHA256` header. Stop if verification fails. ## One-link claim ceremony The CLI defaults to the AWS-owned Product API origin. Register a WorkOS `service_auth` identity; the email is a login hint, not a credential. ```sh qa-army auth agent-register --email you@example.com ``` Use the same `qa-army auth agent-register` command on Windows PowerShell. A non-production API override uses `QA_ARMY_API_URL`, but claimed agent identities are never sent outside `https://api.qa.army`. The CLI registers the identity, creates a single WorkOS claim attempt, and opens the exact `https://app.qa.army/auth/agent/claim` URL in the default browser without putting its token in a child-process argument. Send or approve only that one link. After the user signs in, read the short-lived code from the page and type it once at the CLI's hidden stdin prompt. Never put the code in argv, shell history, a file, logs, or evidence. On success, the CLI completes the claim exactly once, writes the WorkOS assertion and rotating refresh token to the native credential store at service `qa.army.cli`, account `agent-identity`, exchanges the assertion, and verifies the linked QA.army session. The access token is memory-only. Safe output contains identifiers, expiry metadata, and the credential-store location only. If the link is invalid, expired, already claimed, revoked, or denied, discard that attempt and run `agent-register` again to create a new link. Never replay an ambiguous claim-completion request. ## Product requests and deterministic setup Use the OpenAPI document at `https://api.qa.army/v1/openapi.json`. Every authenticated request uses: ```text Authorization: Bearer ``` The reference command composes the documented Workspace, Project, Test generation, Test, and Run operations without exposing the bearer: ```sh qa-army setup \ --app-url https://your-app.example \ --project-name "Your project" \ --prompt "Verify the most important user flow" ``` It reuses one normalized matching Project and generated Test, creates exactly one Run per explicit invocation, waits for the truthful terminal result, and returns the server-owned Project dashboard URL. If multiple Projects match, stop and ask the user to disambiguate before making a mutation. ## Credential lifecycle and errors - On `401`, the CLI discards the memory-only access token, re-exchanges the stored assertion, and retries the same API request exactly once with the same idempotency key. It refreshes first when the assertion is near expiry and atomically replaces the rotated assertion and refresh token in the native store. - On `403`, do not retry or broaden access. Follow the stable `code` and remediation in the problem `title`. An inactive identity link requires a new claim ceremony; a missing `qa:setup` scope requires a new exchange as stated by the response; a capability denial requires a normal signed-in user. - On an expired or invalid refresh credential, start a new claim ceremony. - On a locked, missing, or unavailable native credential store, stop. Do not fall back to plaintext storage, environment variables, stdout, or chat. - On cancellation or an interrupted claim, discard the pending attempt. Do not infer whether claim completion succeeded and do not replay it automatically. - On `5xx` or rate limiting, follow the response and retry only safe reads or idempotent requests. Never automatically retry an ambiguous mutation. Protocol issuer metadata and lifecycle behavior are supplied by WorkOS at `https://heavenly-experience-04.authkit.app/agent/auth.md`; QA.army remains the authority for Projects, Tests, Runs, evidence, billing, and Workspace access.