[FEATURE]: Token-based auth for API-only, non-browser targets (OAuth client_credentials / bearer)
Problem
Shannon's authentication is entirely browser-session based. The validate-authentication
preflight drives Playwright through the login flow and saves a Playwright storageState
(cookies + origins) to auth-state.json; downstream agents restore it with
playwright-cli state-load. login_type accepts api and basic, but
prompts/shared/login-instructions.txt only defines FORM and SSO sections, so those two
enum values produce empty login instructions and no behavior.
That leaves a gap for a common real-world target: an API with no browser login, protected by an OAuth bearer token obtained from a token endpoint (client_credentials, resource-owner password, or refresh_token grant). For these targets there is no form to fill and no cookie session to capture. The token must be:
- fetched from a token endpoint over HTTP (no browser),
- attached as
Authorization: Bearer <token>to the requests the recon/exploit agents make (they issue rawcurlinbash), and - refreshed when it expires — a scan runs ~1–1.5 h while access tokens often live 5–60 min, so a single up-front fetch goes stale mid-run.
A Playwright storageState file cannot express "add this header to curl," so the existing
preflight and shared-session artifact do not cover this case.
Proposed solution
Mirror the existing generate-totp helper pattern with a get-oauth-token CLI baked into
the worker container. It reads the OAuth config, calls the token endpoint, caches the token
with its expiry, and prints a currently-valid access token (refreshing transparently when
near expiry). Agents call it inline exactly as they already call generate-totp:
curl -H "Authorization: Bearer $(get-oauth-token)" https://api.target/endpoint
Sketch of the required pieces:
- Schema (
configs/config-schema.json,types/config.ts): a token-based auth variant carryingtoken_url,grant_type(client_credentials|password|refresh_token),client_id,client_secret,scope,audience, and optionaltoken_header/token_prefix. Makelogin_url/success_conditionoptional for this variant, or add a token-oriented success check (e.g. token endpoint returns 200 withaccess_token). - Helper CLI
get-oauth-tokenunderapps/worker/src/scripts/, symlinked intoPATHin the Dockerfile next togenerate-totp. - Preflight: a token-acquisition branch analogous to
runAuthenticationValidationthat fetches once and fails the run early with a classified error if the grant fails; skips the Playwrightstate-save. - Prompts: an
OAUTH/APIsection inlogin-instructions.txtand a token block in_shared-session.txttelling agents to use$(get-oauth-token)instead of restoring a browser session; guard the browserstate-loadbehind the browser auth types. - Secret handling: pass
client_secretvia env/file rather than prompt text (the same concern raised in #264), and runtoken_urlthrough the existing login-URL safety checks.
Source: KeygraphHQ/shannon