Skip to main content

Authentication

Trinitite authenticates every authenticated request with a single header:

Authorization: Bearer <session_token | api_key>

The platform recognises three classes of principal: human users (session token), machine integrators (API key), and autonomous workloads (Non-Human Identities, presented alongside an API key). Every record returned by the API is filtered to the caller's organization at the data layer — cross-organization access is impossible.


Principals

PrincipalCarrierUse case
Human userSession tokenBrowser dashboard / first-party UI
Machine integratorAPI keyBackend service, CI pipeline, CLI tool
Non-Human Identity (NHI)JIT token + workload origin (alongside an API key)Autonomous AI agent, federated workload

A single request may carry at most one of session token or API key. NHI credentials are sent as additional headers.


Session tokens

Session tokens are issued by the auth lifecycle endpoints. They are short-lived, refreshable, and individually revocable.

MethodPathPurpose
POST/auth/registerRegister a new user (and organization, if standalone)
POST/auth/loginIssue a session token from credentials
POST/auth/refreshRefresh an expiring session
POST/auth/logoutRevoke the current session
GET/auth/meReturn the authenticated user, organization, and roles
POST/auth/send-verification-emailSend (or resend) the email verification link
GET/auth/verify-email?token=...Verify an email address
GET/auth/verification-statusCheck the current user's verification state

Login

curl -X POST https://api.trinitite.ai/auth/login \
-H "Content-Type: application/json" \
-d '{ "email": "ops@acme.com", "password": "..." }'
{
"sessionToken": "sess_01JF8R3M3X4N5Q6T7V8W9Y0Z1A...",
"user": {
"userId": "usr_01JF8...",
"email": "ops@acme.com",
"displayName": "Acme Ops"
},
"organization": {
"organizationId": "org_01JF8...",
"organizationName": "Acme"
},
"roles": ["developer"]
}

To list and revoke sessions, see the Sessions API.

Sessions are required for some endpoints

User, role, and organization management endpoints (e.g. POST /v1/users, PATCH /v1/organization) accept only session tokens, not API keys. Programmatic principals cannot create users.


API keys

API keys are long-lived machine credentials bound to your organization, issued from a session and managed through the API key endpoints. Each key carries an explicit scope list matched against the permission required by every endpoint it touches.

Authorization: Bearer trit_live_4f8d9e2a1c6b7f3a9e1d2c4b5a6f7e8d
Keep keys secret
  • Never commit API keys to version control.
  • Never expose keys in client-side code.
  • Use environment variables — TRINITITE_API_KEY.
  • Rotate every 90 days, or immediately on suspected compromise.

Create an API key

POST /auth/api-keys — session-authenticated.

FieldTypeRequiredDescription
labelstringYesHuman-readable label (e.g. production, ci-runner)
scopesstring[]YesPermission scopes (see § Permission scopes)
expires_atstring (RFC 3339)NoOptional explicit expiry
curl -X POST https://api.trinitite.ai/auth/api-keys \
-H "Authorization: Bearer $TRINITITE_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "production-pii-redactor",
"scopes": ["guardians:read", "logs:read"]
}'
{
"key_id": "key_01JF8R3M3X4N5Q6T7V8W9Y0Z1A",
"label": "production-pii-redactor",
"scopes": ["guardians:read", "logs:read"],
"plaintext_key": "trit_live_4f8d9e2a1c6b7f3a9e1d2c4b5a6f7e8d",
"created_at": "2026-05-01T22:14:33Z",
"expires_at": null
}
plaintext_key is only returned once

plaintext_key is shown one time on creation. Store it in your secrets manager immediately. The platform stores only a hashed copy.

List API keys

GET /auth/api-keys — accepts session token or API key (with api_keys:read).

{
"data": [
{
"key_id": "key_01JF8...",
"label": "production-pii-redactor",
"prefix": "trit_live_4f8d",
"scopes": ["guardians:read", "logs:read"],
"status": "active",
"created_at": "2026-05-01T22:14:33Z",
"last_used_at": "2026-05-01T23:41:08Z",
"expires_at": null
}
],
"page": { "next_cursor": null, "has_more": false }
}

Inspect effective features

GET /auth/api-keys/{keyId}/effective-features

Returns the entitlements available to a specific key (computed from organization plan + key scopes). Use this when debugging unexpected 403 entitlement_denied responses.

Revoke an API key

DELETE /auth/api-keys/{keyId} — session-authenticated.

Revoked keys immediately return 401 unauthenticated on every subsequent request. Revocation is permanent — generate a new key to replace it.

{ "message": "API key revoked", "key_id": "key_01JF8...", "revoked_at": "2026-05-01T23:55:00Z" }

Permission scopes

Permissions are strings of the form resource:action. An endpoint declares the permission it requires; the platform compares it against the caller's scopes.

PermissionGrants
guardians:readList, view, and call Guardians
guardians:createCreate Guardians
guardians:writeUpdate / soft-delete Guardians
guardians:adminPower operations (e.g. force-ready)
logs:readRead the Glass Box Ledger
policies:read / policies:writePolicy documents and their nodes
mcp:read / mcp:writeMCP gateway servers, bindings, OAuth
nhi:read / nhi:writeNon-Human Identities
compliance:read / compliance:writeCompliance frameworks, evidence, DSR
reports:read / reports:writeEnterprise reports
skills:read / skills:writeSkill Vault
cli:read / cli:createCLI Firewall (read; execute)
api_keys:read / api_keys:writeAPI key inventory
audit_logs:readAuditor activity / governance audit log

Two wildcard forms are recognised:

  • <resource>:* — all actions on a single resource (e.g. guardians:*).
  • * or *:* — all actions on all resources. Reserved for the built-in admin system role and explicitly elevated keys.

System roles ship pre-defined and immutable: admin, auditor, developer, viewer. See Roles API for the complete catalogue and how to define custom roles.


Non-Human Identity (NHI) headers

Autonomous workloads — AI agents, federated identities, MCP clients — present an NHI alongside their API key. Two header pairs are accepted:

X-Trinitite-Nhi-Token: <jit_token>
X-Trinitite-Workload-Origin: <origin_descriptor>

or, for re-use of a previously issued NHI:

X-Trinitite-Nhi-Id: <nhi_id>
X-Trinitite-Workload-Origin: <origin_descriptor>

The platform validates the JIT token, confirms the workload origin matches the NHI's registered origin, attaches the NHI's privilege tier to the request context, and enforces tier-based filtering on the response. Issue NHI tokens via POST /v1/proxy/nhi/tokens — see the Identities reference.

When proxying upstream LLM traffic, also include X-Trinitite-Credential-Id to identify the vaulted provider credential — see Provider Credentials.


Organization scope

The organization is always derived from the credential. Cross-organization requests are not possible: every record returned by the API is filtered to the caller's organization at the data layer. Multi-tenant deployments are isolated at the row level. Any organizationId field in a request body is ignored.


Unauthenticated endpoints

The following endpoints accept no authentication and are safe for public exposure:

EndpointPurpose
GET /metricsPrometheus exposition
GET /health / /health/liveness / /health/readinessOperational probes
GET /.well-known/jwks.jsonPublic-key bundle for verifying issued artifacts
GET /.well-known/oauth-protected-resourceOAuth 2.1 metadata for the MCP Gateway
GET /v1/public/jwksAlias of the JWKS endpoint
GET /v1/public/verify/*Stateless attestation-bundle verification
GET /v1/public/attestations/{public_id}Operator-published attestation lookup

See Public Verification for full details on the verifier surface.


Standard request headers

HeaderRequiredPurpose
AuthorizationConditionalSession token or API key
X-Trinitite-Nhi-Token / X-Trinitite-Nhi-IdConditionalNHI principal headers
X-Trinitite-Workload-OriginConditionalRequired alongside any NHI header
X-Trinitite-Credential-IdConditionalRequired on /v1/proxy/*
Idempotency-KeyOptionalSee § Idempotency
Content-TypePOST / PATCHapplication/json unless documented otherwise
AcceptOptionalapplication/json default; some exports accept application/pdf, text/csv, application/oscal+json
X-Request-IdOptionalClient correlation ID; echoed back

Standard response headers

HeaderAlwaysPurpose
X-Request-IdYesStable correlation ID; matches error.request_id
X-RateLimit-LimitOn rate-limited surfacesQuota for the current window
X-RateLimit-RemainingOn rate-limited surfacesRequests remaining in the current window
X-RateLimit-ResetOn rate-limited surfacesUnix epoch seconds at which the window resets
Retry-AfterOn 429 and select 503Seconds to wait before retrying
ETagOn versioned resourcesUse with If-Match for optimistic-concurrency PATCH
Deprecation / SunsetWhen applicableRFC 8594 deprecation signalling

Error envelope

Every error response — regardless of HTTP status — uses a single JSON shape:

{
"error": {
"code": "string",
"message": "human readable description",
"details": { },
"request_id": "req_01J9X..."
}
}
FieldDescription
error.codeStable machine-readable code (snake_case). Safe to switch on
error.messageHuman-readable description; may vary across releases
error.detailsEndpoint-specific structured context (validation paths, missing scopes, conflict markers)
error.request_idCorrelates with X-Request-Id and the audit log

Common codes

HTTPerror.codeMeaning
400validation_errorBody or query failed schema validation. details lists field paths
400bad_requestSemantic precondition violated
401unauthenticatedMissing or invalid credential
403forbiddenAuthenticated but lacking the required permission. details.required_permission set
403entitlement_deniedCaller's organization is missing a required entitlement
404not_foundResource does not exist or is outside caller's organization
409conflictResource state precludes the requested transition
409idempotency_conflictIdempotency key reused with a different request body
410resource_goneHard-deleted resource
422unprocessable_entityDomain-level validation failed
429rate_limitedPer-organization rate limit exceeded
500internal_errorUnexpected platform error. Safe to retry with backoff
502 / 504upstream_error, upstream_timeoutDownstream LLM provider, MCP server, or training service failed
503emergency_shutdownOrg-wide emergency kill switch is engaged

Rate limits

Authenticated endpoints are rate-limited per organization. Health and metrics endpoints are exempt. Read the headers on every response:

X-RateLimit-Limit: 500
X-RateLimit-Remaining: 487
X-RateLimit-Reset: 1746139200

On 429:

{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Retry after 60 seconds.",
"request_id": "req_01J..."
}
}
Retry-After: 60

Retry guidance:

  • On 429, wait for Retry-After before retrying. Do not retry sooner — the limiter is a hard bucket.
  • On 5xx, use exponential backoff with jitter starting at 1 s, capping at 30 s.
  • Idempotent retries are safe for GET, PUT, DELETE, and any POST carrying an Idempotency-Key header.

Idempotency

Mutating endpoints (POST, PATCH, DELETE) accept an idempotency key:

Idempotency-Key: <uuid-or-stable-string>
  • First call with a given key: the platform processes the request and stores the response.
  • Repeat call within 24 hours, byte-identical body: the original response is returned (same status, same body).
  • Repeat call within 24 hours, different body: 409 idempotency_conflict with the original request_id in details.
  • After 24 hours the key is forgotten.

GET requests are inherently idempotent and do not require the header.


Pagination

List endpoints use cursor-based pagination by default.

GET /v1/logs?limit=100&cursor=<opaque>
{
"data": [ /* items */ ],
"page": {
"next_cursor": "string | null",
"has_more": true
}
}

A small set of legacy endpoints (notably GET /v1/guardians, GET /v1/users, GET /v1/roles) use offset pagination (limit + offset). Each endpoint's reference page documents which form it uses.


Versioning & deprecation

  • Endpoints are versioned in the path (/v1/...). Breaking changes ship under a new path prefix.
  • Additive changes — new optional request fields, new response fields, new enum values, new endpoints — do not trigger a path bump. Clients must ignore unknown response fields.
  • Deprecated endpoints emit Deprecation: true and Sunset: <RFC 1123 date> headers (RFC 8594).
  • Removal lead time is at least 12 months from the first Deprecation header.

Verify your credential

curl -X GET https://api.trinitite.ai/v1/guardians \
-H "Authorization: Bearer $TRINITITE_API_KEY"

A 200 OK response confirms the credential is live. A 401 unauthenticated means the credential is missing, malformed, expired, or revoked. A 403 forbidden means the credential is valid but lacks guardians:read.


Next steps