Core concepts
The primitives Qeet ID is built on — tenants & organizations, users, principals, sessions, and roles — and how identity flows between them.
Qeet ID is a multi-tenant identity platform. Almost everything is scoped to a tenant and acts on a principal (a user or a machine identity). This page is the mental model the rest of the docs assume.
Tenants & organizations
A tenant is the unit of isolation — a workspace/organization. Every resource
(users' memberships, roles, sessions, SSO connections, audit events) is scoped by
tenant_id, enforced everywhere. A personal tenant is auto-created when someone
signs up, so a single user always has a home.
A user can belong to multiple tenants. switch-tenant re-mints a scoped access
token for a different tenant the user is a member of.
/v1/tenantsCreate a tenant/v1/auth/switch-tenantSwitch active tenantconst tenant = await qeetid.tenants.create({ name: "Acme, Inc." });Tenant configuration lives under /v1/tenants/{tenantID} — auth
policy, branding, email templates, IP rules, retention, and SSO connections are all
per-tenant. See Multi-tenancy.
Users
A user is a stable identity with a canonical id (usr_… / UUID), profile, and
verified contact methods (email, phone). Email is globally unique. Users support:
- CRUD + cursor pagination, soft-delete with a recycle bin (restore / purge).
set-password, email/phone verification, and linked external identities (social / SAML / LDAP).- Free-form metadata you control.
/v1/usersList users (cursor paginated)/v1/users/{id}/restoreRestore a soft-deleted userconst user = await qeetid.users.create({ email: "alex@acme.com", display_name: "Alex Chen" });Principals & machine identities
A principal is whoever is acting: a human user, or a machine identity. Qeet ID ships two machine-identity models:
- API keys — scoped, expirable, hashed credentials your backend sends as
Authorization: ApiKey qk_…. - Service principals + OAuth
client_credentials— for M2M clients that need an access token via the OAuth token endpoint.
This shared principal model is what makes scoped, auditable non-human access (and, ahead, AI-agent delegation) first-class. See API keys & service principals.
Sessions & tokens
A session represents an authenticated client. Authentication issues a token pair:
- Access token — a short-lived ES256 JWT. Verify it offline against the
public JWKS (
/.well-known/jwks.json). Carriesuser_id,tenant_id,session_id. - Refresh token — exchanged at
/v1/auth/refreshfor a fresh pair, with rotation + theft detection: replaying a rotated refresh token revokes the whole chain and audits it.
Sessions can be listed and revoked individually. See Sessions.
{
"access_token": "eyJhbGciOiJFUzI1Ni…",
"token_type": "Bearer",
"expires_at": "2026-06-04T12:15:00Z",
"refresh_token": "…",
"session_id": "…",
"user_id": "…",
"tenant_id": "…"
}Roles & permissions
Permissions are strings like billing:write. Roles bundle permissions and
are assigned to a user or a group within a tenant; effective permissions are
direct ∪ group-derived. A single call answers "may this principal do X?":
/v1/checkAuthorize an actioncurl "https://api.qeetid.com/v1/check?user_id=$U&tenant_id=$T&permission=billing:write" \
-H "Authorization: ApiKey $QEETID_API_KEY"
# → { "allowed": true }Add ?explain=true to get the grant-path trace (which role/group allowed it, or
why it was denied). See Authorization.
How it fits together
┌──────────────────────┐
│ Tenant │
│ policy · branding · │
│ SSO · audit · keys │
└───────────┬───────────┘
membership + │
role/group │
┌───────────────┬─────┴───────┬───────────────┐
▼ ▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────────────┐
│ User │ │ Machine │ │ Session │ │ Role/Group │
│ (principal)│ │ identity │ │ (tokens) │ │ → perms │
└─────┬─────┘ └─────┬─────┘ └────┬─────┘ └──────┬───────┘
└───────────────┴────────────┴───────────────┘
▼
Tamper-evident audit log
(hash-chained · /verify · webhooks)