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​