Authentication
Aletheia’s API supports three authentication schemes, each for a different kind of caller. Pick the one that matches how your code runs.
Bearer tokens — for programmatic clients
Section titled “Bearer tokens — for programmatic clients”This is the scheme for CLIs, scripts, and server-to-server integrations.
Obtain an access token from POST /api/v1/auth/login. The response body carries
access_token, refresh_token, access_expires_at, and refresh_expires_at.
Send it on every request:
Authorization: Bearer <access token>Bearer-authenticated requests are exempt from CSRF. That is not a shortcut: CSRF protection exists because browsers attach cookies automatically, and a header your code sets deliberately cannot be forged by a third-party site.
When the access token expires, exchange the refresh token at
POST /api/v1/auth/refresh, sending it in the body:
{ "refresh_token": "<refresh token>" }Session cookies — for browsers
Section titled “Session cookies — for browsers”The web interface authenticates with HttpOnly cookies the API sets at login:
| Cookie | Contains | Path |
|---|---|---|
critias_at |
Access token | /api/v1 |
critias_rt |
Refresh token | /api/v1/auth |
critias_csrf |
CSRF token | / |
critias_at and critias_rt are HttpOnly, so JavaScript cannot read them — which
is what makes a cross-site script unable to steal the session. All three are
SameSite=Strict, and Secure in production.
Because the browser attaches those cookies automatically, cookie-authenticated
mutating requests must also prove the request came from your page. That is the
double-submit CSRF check: read the critias_csrf cookie (it is deliberately not
HttpOnly) and send its value back as a header:
X-CSRF-Token: <value of the critias_csrf cookie>The API compares the two in constant time. Safe methods — GET, HEAD,
OPTIONS, TRACE — are exempt.
If the header is missing or does not match, the request fails with 403 and code
csrf_failed.
Ingest tokens — for CI
Section titled “Ingest tokens — for CI”CI pipelines use a separate credential that reaches only the /api/v1/ingest/*
endpoints:
Authorization: Bearer <ingest token>Despite the identical header shape, this is not a user token: it cannot read your inventory or call any other endpoint. See Ingest tokens.
Choosing a scheme
Section titled “Choosing a scheme”| If you are | Use |
|---|---|
| Writing a script or CLI | Bearer tokens |
| Building a browser app against the API | Session cookies plus CSRF |
| Wiring a CI pipeline | Ingest tokens |
Do not use session cookies from a non-browser client. You would be taking on the CSRF handshake for no benefit.
Unauthenticated endpoints
Section titled “Unauthenticated endpoints”A few endpoints take no credential by design:
POST /api/v1/auth/signupandPOST /api/v1/auth/login— you have none yet.- The invitation endpoints — the single-use invitation token in the path is the credential.
GET /api/v1/scm/github/callback— a browser redirect target, verified by a signed state token.POST /api/v1/webhooks/githubandPOST /api/v1/webhooks/gitlab— verified by a per-connection signature on each delivery, not by a bearer credential.
Where to go next
Section titled “Where to go next”- Errors and error codes for what failures look like.
- Roles and permissions for what a token is allowed to do once authenticated.