APIs

REST identity

This page is the identity surface of the REST API: how a caller becomes a subject, how that subject is scoped to a tenant, and how roles become permissions.

Task-oriented walkthroughs: Issue an API token, Connect an identity provider.

Sessions

MethodPathAuthPurpose
POST/auth/loginPublicUsername + password → access + refresh
POST/auth/refreshPublicRotate the pair
POST/auth/logoutSessionRevoke this session
POST/auth/logout-allSessionRevoke every session for the subject
GET/auth/sessionsSessionList active sessions
GET/auth/configAuthenticatedLive auth posture (what is wired)

Login body: { "tenant_id", "username", "password" }.

Response: access_token (sess_…), refresh_token, expires_at, subject_id, tenant_id. Access tokens are short-lived (15 minutes by default). Refresh rotates both tokens — do not reuse the old refresh token.

PAIR=$(curl -s -X POST "$SIRIUS/auth/login" \
  -H 'content-type: application/json' \
  -d '{"tenant_id":"default","username":"admin","password":"password"}')

ACCESS=$(echo "$PAIR" | jq -r .access_token)
REFRESH=$(echo "$PAIR" | jq -r .refresh_token)

curl -s -X POST "$SIRIUS/auth/refresh" \
  -H 'content-type: application/json' \
  -d "{\"refresh_token\":\"$REFRESH\"}"

On 401 with a session, refresh once and replay. Do not loop.

API tokens

MethodPathPermission
GET/api-tokens?tenant_id=runtime:identity:read
POST/api-tokensruntime:identity:write
DELETE/api-tokens/{id}?tenant_id=runtime:identity:write

Mint body: { "tenant_id", "name", "roles": [], "expires_in_days"? }. Response includes secret once and metadata (id, prefix, roles, expires_at, revoked). List never returns the secret. Revocation is immediate and idempotent.

Send Authorization: Bearer sk_… or X-API-Key: sk_…. The token authenticator defers on anything that is not sk_, so sessions and OIDC keep working.

Identity providers

Runtime-mutable. A primary OIDC provider stored here takes precedence over SIRIUS_AUTH_OIDC_*.

MethodPathPermission
GET / POST/identity/providersread / write
GET / DELETE/identity/providers/{id}read / write
POST/identity/providers/{id}/testread
GET/identity/providers/{id}/planread
GET / PUT/identity/break-glassread / write
POST/identity/break-glass/rotatewrite

POST body for OIDC includes kind, primary, issuer, audiences, optional jwks_url, claim mappings, and default_tenant. Test validates configuration without opening a network session. Plan shows what will change on save. Providers hot-reload.

Break-glass is stored hashed. PUT sets it; rotate issues a new secret (shown once). An expired console key falls through to the deployment env key rather than shadowing it.

Users, groups, roles

PrefixWhat it manages
/usersPeople and service-account metadata
/groupsGroups, members, IdP claim mappings
/roles, /permissions, /role-grantsRole definitions and grants
/tenantsTenant registry and key policy

Creating a user (POST /users) confers no access. Grant roles (POST /role-grants) or add the subject to a group. Effective permissions are the union of direct grants, group roles, and JIT claim mappings (/groups/claim-mappings).

curl -s -X POST "$SIRIUS/users" -H 'content-type: application/json' -d '{
  "tenant_id":"default","subject_id":"svc-ci","type":"service","name":"CI"
}'

curl -s "$SIRIUS/role-grants/svc-ci/effective-permissions?tenant_id=default"

identity:manage is high privilege: a group confers its roles to every member. Treat it like role:manage.

How a request becomes a tenant

  1. tenant_id in the body (writes) or query string (reads)
  2. The authenticated subject’s tenant
  3. X-Sirius-Tenant

Cross-tenant access is 404 not_found. * is account-wide and needs elevated permission. A federated subject with an all-tenants claim may adopt X-Sirius-Tenant; a single-tenant subject cannot.

Discovery

GET /agent/tools?category=identity lists every identity operation with method, path, permission, and input schema. That catalog is generated from the runtime.