Authentication¶
Vex Raptor's REST API under /api/v1 uses two credential types: JWT bearer
tokens for interactive/user calls, and org API keys for automation (CI).
Session tokens (JWT)¶
Interactive clients log in with email + password (or SSO) and receive a JWT.
curl -sS -X POST https://<host>/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"..."}'
{
"status": "success",
"token": "<JWT>",
"refresh_token": "<JWT>",
"role": "admin",
"org_id": 42,
"org_plan": "enterprise"
}
The response also sets two httpOnly session cookies (vex_access / vex_refresh)
— see Browser sessions below. The Vex Raptor web
app relies on those; anything calling the API directly can ignore them and just
use token as a Bearer credential.
Send the token on every subsequent request:
Token characteristics:
| Property | Value |
|---|---|
| Algorithm | HS256, signed with your SECRET_KEY |
| Lifetime | 2 hours (access) · 7 days (refresh) |
| Claims | sub, role, org_id, jti, iat, exp |
| Revocation | jti is checked against a server-side blocklist on every request |
Logout revokes the current token immediately:
Store tokens safely
Treat the JWT as a bearer secret. Do not log it, embed it in URLs, or commit
it. If you're calling the API directly (not through the Vex Raptor web app),
prefer the Authorization header over reading or setting the session
cookies described below yourself.
Browser sessions (cookies)¶
The Vex Raptor web app does not store tokens in localStorage. Since FE-01,
/api/v1/auth/login and /api/v1/auth/refresh also set two httpOnly session
cookies — the browser never gets JS-level access to the raw JWT:
| Cookie | Contents | Lifetime | Path |
|---|---|---|---|
vex_access |
Access token (same JWT as token above) |
2 hours | / |
vex_refresh |
Refresh token | 7 days | /api/v1/auth only |
Both cookies are HttpOnly, SameSite=Strict, and Secure in production/staging
(not marked Secure in local http:// dev). vex_refresh is scoped to
/api/v1/auth only — it isn't sent on ordinary API calls, just the login/
refresh/logout endpoints.
Every authenticated endpoint accepts either an Authorization: Bearer <JWT>
header or the vex_access cookie — the header takes precedence when both
are present. API/CI clients keep using the Bearer header exactly as documented
above; only the first-party web app relies on the cookie.
/api/v1/auth/logout clears both cookies in addition to revoking the token
server-side (jti blacklist).
Auth-specific errors¶
| Status | detail |
Cause |
|---|---|---|
401 |
Not authenticated |
No Authorization header and no vex_access cookie |
401 |
Invalid auth token |
Token expired, malformed, or signature mismatch |
401 |
Refresh token revoked |
Refresh token already used/blacklisted (rotation) |
401 |
Refresh token expired |
Past its 7-day lifetime — log in again |
503 |
Auth service temporarily unavailable |
Token revocation store unreachable during refresh |
See Errors, rate limits & versioning for the general error model.
SSO / OIDC¶
On enterprise plans, users authenticate through your identity provider. The id-token signature is verified against your IdP's JWKS before a session is issued. See SSO & RBAC.
Org API keys (automation)¶
CI and machine-to-machine calls use a per-org API key sent in X-Vex-Key
instead of a JWT.
curl -sS -X POST https://<host>/api/v1/webhook/scan \
-H "X-Vex-Key: <org-api-key>" \
-H "Content-Type: application/json" \
-d '{"target":"https://staging.example.com","fail_on":"high"}'
API keys are:
- Scoped to a single org and a defined set of actions.
- Revocable at any time from the console (revocation is immediate).
- Rotatable — issue a new key, deploy it, then revoke the old one.
See managing API keys.