Authentication
Raven accepts three kinds of credentials. All are sent as Authorization: Bearer <token>. For an API key, X-Subscription-Token: <key> also works.
| Credential | Looks like | Get it from | Use it for |
|---|---|---|---|
| API key | rvn_live_… |
The dashboard, the CLI, or the device flow | Scripts, the REST API, MCP clients without OAuth |
| OAuth access token | rvn_at_… (expires in 1 hour) |
An MCP client's OAuth sign-in | MCP clients such as Claude Code, Codex and Gemini CLI |
| Browser session | a cookie | Signing in at ravenoutreach.com | The dashboard |
API keys
An account can have up to 10 keys. Only a hash of each key is stored, so a key is shown once, when it's created. Keys have the read and write scopes. Revoke a key in the dashboard. A tool holding a key can also revoke it itself, with POST /oauth/revoke token=<key>.
Never put a key in code or a commit. Keep it in a gitignored .env as RAVEN_API_KEY, in your OS keychain (the CLI does this), or in your agent's secret store.
Device flow
The device flow (RFC 8628) is how a CLI or coding agent signs a user up or in. The user clicks one link in a browser, and the agent receives an API key. A new account gets the free credit.
curl -s -X POST https://api.ravenoutreach.com/oauth/device/code \
-d client_id=my-agent -d "client_name=My agent on $(hostname -s)"
{"device_code": "rvn_dc_…", "user_code": "WDJB-MJHT",
"verification_uri": "https://ravenoutreach.com/activate",
"verification_uri_complete": "https://ravenoutreach.com/activate?code=WDJB-MJHT",
"expires_in": 900, "interval": 5}
Show the user verification_uri_complete and the user_code. The approval page shows the same code, so they can check it matches. Then poll the token endpoint every interval seconds:
curl -s -X POST https://api.ravenoutreach.com/oauth/token \
-d grant_type=urn:ietf:params:oauth:grant-type:device_code \
-d device_code=rvn_dc_… -d client_id=my-agent
| Response | Meaning |
|---|---|
{"error": "authorization_pending"} |
Keep polling. |
{"error": "slow_down"} |
Poll 5 seconds less often. |
{"error": "access_denied"} |
The user declined. Stop. |
{"error": "expired_token"} |
15 minutes passed. Start again. |
{"access_token": "rvn_live_…", "token_type": "Bearer", …} |
Done. The key is handed out once. |
OAuth for MCP clients
MCP clients that support MCP authorization need only Raven's MCP URL. The flow:
- The client calls
https://api.ravenoutreach.com/mcpwithout a token and gets a401. ItsWWW-Authenticateheader points to the resource metadata. - The client registers itself and sends the user to a consent page.
- The user approves with one click. If they're new, they sign up first.
| Protected resource metadata | https://api.ravenoutreach.com/.well-known/oauth-protected-resource/mcp |
| Authorization server metadata | https://api.ravenoutreach.com/.well-known/oauth-authorization-server |
| Registration | Dynamic client registration (RFC 7591) at /oauth/register; public clients only (no secret) |
| Grant | Authorization code with PKCE (S256 only); responses include iss (RFC 9207) |
| Redirect URIs | https anywhere, http only for loopback addresses (any port), or a desktop app's own scheme |
| Scopes | read (account, teams, leads), write (create and steer teams, which spends credit) |
| Resource indicators | https://api.ravenoutreach.com/mcp (the default) or https://api.ravenoutreach.com (the REST API); a token works only at the resource it was issued for |
| Tokens | Access tokens last 1 hour. Refresh tokens last 30 days and rotate on every use. Replaying a used refresh token revokes the whole chain. |
| Revocation | POST /oauth/revoke (RFC 7009); users can also disconnect apps in the dashboard |