Login
Two flows, pick whichever fits:
- Browser flow (default) — opens your default browser, you approve once, CLI gets a 90-day API key
- Device flow (
--device) — no local browser needed; works on SSH, tmux, CI runners
Both end the same way: a sk-... API key stored at ~/.cybrium/config.yml with scopes scan:upload, findings:write, findings:read.
Browser flow
cybrium login
What happens:
- The CLI generates a PKCE verifier + S256 challenge.
- Binds a local listener on
127.0.0.1:<random-port>/callback. - Opens your default browser to
https://app.cybrium.ai/cli-approvewith state + challenge in the query string. - You confirm the scopes in the browser. If you're not signed in yet, you'll bounce through the normal login first.
- The SPA POSTs an approval to the server, gets a one-time auth code, and 302-redirects to
127.0.0.1:<port>/callback?code=...&state=.... - The CLI's listener receives the code, exchanges it for an API key using PKCE, and writes it to
~/.cybrium/config.yml. - Browser shows a ✓ "Cybrium CLI signed in" page — you can close the tab.
$ cybrium login
Opening browser to authorize the CLI…
If the page doesn't open, visit:
https://app.cybrium.ai/cli-approve?code_challenge=...
✓ Logged in. API key stored at /Users/me/.cybrium/config.yml
scopes: scan:upload findings:write findings:read
tenant: 1
expires: 2026-07-13
Device flow
cybrium login --device
What happens:
- The CLI POSTs to
/api/auth/cli/device/code/and gets back auser_code(looks likeWDJB-MJHT) and adevice_code. - CLI prints the code and opens the verification URL.
- You go to
https://app.cybrium.ai/activateon any device, enter the user_code (or use the pre-filled URL), and approve. - Meanwhile, the CLI polls
/api/auth/cli/token/every 5 seconds. Once you approve, the next poll returns the API key and stores it.
$ cybrium login --device
1. Visit: https://app.cybrium.ai/activate
2. Enter: WDJB-MJHT
(or open the pre-filled URL: https://app.cybrium.ai/activate?code=WDJB-MJHT)
......
✓ Logged in. API key stored at /Users/me/.cybrium/config.yml
Local / dev stacks
For developing against a local backend:
CYBRIUM_API=http://localhost:8000/api \
CYBRIUM_WEB=http://localhost:3001 \
cybrium login
CYBRIUM_API— API base URL (defaulthttps://app.cybrium.ai/api)CYBRIUM_WEB— Console URL for OAuth consent (default: derived from API host)
In production the two share a host and CYBRIUM_WEB isn't needed.
After login
cybrium whoami
Email: you@example.com
Name: Your Name
Tenant: Acme Corp
Role: admin
The stored token is a tenant-scoped API key — it can ingest scans + read/write findings for that tenant only.
Logout
cybrium logout
Clears the token from your config file. The key itself isn't server-side revoked — delete it explicitly from Settings → API Keys in the platform UI if you want it dead everywhere.
Troubleshooting
timed out waiting for browser approval
The loopback server waits 5 minutes. Most common cause: corporate proxy or browser popup blocker.
Workaround: use --device instead.
PKCE verifier mismatch
You probably restarted the CLI mid-flow. Re-run cybrium login.
Device approved but CLI never finishes
Verify the CLI is still running and reachable to the internet. The device-code poll hits /api/auth/cli/token/ every 5 seconds; network issues show as timeouts here.
Wrong tenant after login
organization_id is auto-bound from the browser session tenant. To target a different one, switch tenants in the web UI before clicking Approve — or use --web to point at a specific tenant subdomain.