Skip to main content
The auth service runs on port 8001 and handles token lifecycle management. It is not called on the hot path — only for management operations. Base URL: http://localhost:8001 (dev) / AUTH_SERVICE_URL (production)

Health

GET /health

Health check endpoint. Response 200 OK:
{
  "status": "healthy",
  "service": "quint-auth"
}

Tokens

POST /tokens/app

Create an app token (management-plane root).
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Production API",
  "scopes": ["*"],
  "ttl_days": 365
}

POST /tokens/bearer

Derive a bearer token from an app token.
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000",
  "app_token_hash": "sha256-hash-of-app-token",
  "environment": "production",
  "ttl_days": 90
}

POST /tokens/agent

Derive an agent token from a bearer token with RBAC policy.
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000",
  "bearer_jti": "jti-of-bearer-token",
  "agent_id": "code-review-agent",
  "agent_name": "Code Review Agent",
  "rbac": {
    "allowed_actions": ["data:read:*", "code:review:*"],
    "denied_actions": ["data:write:*"],
    "allowed_resources": ["repo:*"],
    "denied_resources": [],
    "max_sensitivity_level": 3
  },
  "ttl_hours": 24
}

POST /tokens/subagent

Derive a subagent token from an agent token with permission narrowing.
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000",
  "parent_agent_jti": "jti-of-agent-token",
  "agent_id": "lint-subagent",
  "agent_name": "Lint Subagent",
  "rbac": {
    "allowed_actions": ["code:read:*"],
    "denied_actions": ["data:write:*", "code:deploy:*"],
    "allowed_resources": ["repo:frontend"],
    "denied_resources": [],
    "max_sensitivity_level": 2
  },
  "ttl_hours": 4
}

POST /tokens/session

Create a session token bound to an agent or subagent.
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000",
  "parent_jti": "jti-of-agent-or-subagent",
  "parent_type": "agent",
  "session_id": "session-2026-02-26-abc",
  "max_events": 1000,
  "ttl_minutes": 60
}

POST /tokens/override

Create an ephemeral override token for a held high-risk event.
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_id": "event-uuid",
  "allowed_decisions": ["approve", "reject"],
  "reason": "High-risk data access flagged by scoring pipeline",
  "ttl_minutes": 5
}

Revocation

DELETE /tokens/{jti}

Revoke a single token by JTI. Adds it to the bloom filter and revocation log. Response 200 OK:
{
  "jti": "revoked-token-jti",
  "status": "revoked"
}

POST /revoke/cascade/{jti}

Revoke a token and all tokens derived from it (children, grandchildren, etc.). Response 200 OK:
{
  "root_jti": "parent-token-jti",
  "revoked_count": 5,
  "revoked_jtis": ["jti1", "jti2", "jti3", "jti4", "jti5"]
}

POST /bloom/rebuild

Rebuild the bloom filter from the auth.revocation_log table. Used after Redis data loss or for periodic maintenance. Response 200 OK:
{
  "rebuilt": true,
  "entries": 1234
}

Signing Keys

POST /keys/signing

Generate a new ES256 signing key pair for a customer.
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000"
}

POST /keys/{key_id}/rotate

Rotate a signing key — generates a new key and deactivates the old one. Request:
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000"
}
Response 200 OK: Same as POST /keys/signing.

GET /keys/public/{customer_id}

Get the active public key for a customer. Used by the API service to populate its in-memory key cache. Response 200 OK:
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000",
  "public_key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
  "key_id": "key-uuid"
}

Webhooks

POST /webhooks/register

Register a webhook endpoint for a customer.
{
  "customer_id": "550e8400-e29b-41d4-a716-446655440000",
  "endpoint_url": "https://example.com/webhooks/quint"
}

Overrides

POST /overrides/{event_id}/decide

Submit an approve/reject decision for a held event using an override token.
{
  "override_token": "qt_override_eyJ...",
  "decision": "approve",
  "reason": "Authorized by team lead after review"
}

Error Responses

All error responses follow a consistent format:
{
  "detail": "Human-readable error message"
}
StatusMeaning
400Bad request (invalid payload, permission escalation)
401Authentication failed (expired, invalid, revoked token)
403Authorization denied (RBAC violation)
404Token or resource not found
429Rate limit exceeded
503Service unavailable (validator not initialized)