Skip to content
Talk to our solutions team

Identity entities

iam.svc ships 29 entities as an embedded schema, materialized per tenant at engine build. This page is the field-level reference: what each entity holds, who may touch it, whether a product or tenant may extend it, and which ones nothing in the service actually reads.

Each entity lands in one of three isolation planes, selected by its scope: key.

Planescope:Where it livesEntities
TenantunsetThe tenant’s own PostgreSQL schemaEverything not listed below
ControlsuperadminA separate schema named superadmin, split out at boottenant, tenant_eventlog, superadmin, superadmin_grant
SharedsharedA shared scope engineNone of the base entities use it

jwt_signing_key and user_refresh_token are tenant-plane entities that are additionally cloned into the control plane with scope forced to superadmin, so operator credentials never share a table with a tenant’s.

Extends says what a product or tenant layer may contribute: no means final: true (sealed against every layer), fields means new fields only, fields + access means new fields plus access tiers not named in access-lock:.

EntityTablePlaneHolds
principaliam_principaltenantThe registry: one row per principal, its kind, and where its detail lives
credentialsiam_principal_credentialtenantEvery way a principal authenticates, local or federated
principal_grantiam_principal_granttenantGrants between principals, including delegation
usersiam_principal_usertenantThe base identity row
iamagentsiam_principal_agenttenantAgent principals: the agent of an app connection
iambotsiam_principal_bottenantBot principals with claims
bot_memberiam_bot_membertenantWho belongs to a bot
iamservicesiam_principal_servicetenantService principals
iamdelegationsiam_principal_delegatetenantUser-to-user delegation grants
peer_actorsiam_peer_actortenantActors seen from another plane
roleiam_roletenantRole definitions
sessioniam_sessiontenantManaged server-side sessions
challengesiam_auth_challengetenantIn-flight authentication challenges, of every kind
user_refresh_tokeniam_refresh_tokentenant + controlRotating refresh-token families
api_keyiam_api_keytenantIssued service API keys
user_mfa_requestiam_user_mfa_requesttenantTOTP enrolments
user_magic_linkiam_user_magic_linktenantMagic-link codes
password_reset_requestiam_password_reset_requesttenantPassword-reset codes
oauthstateiam_oauth_statetenantOAuth state and PKCE verifier
providerconfigsiam_provider_configtenantIdentity-provider endpoints and settings
webauthn_credentialiam_webauthn_credentialtenantRegistered passkeys
webauthn_sessioniam_webauthn_sessiontenantIn-flight WebAuthn challenge
jwt_signing_keyiam_token_signing_keytenant + controlThe per-tenant signing keyring
impersonation_requestsiam_impersonation_requesttenantImpersonation grants and their audit
user_eventlogiam_user_eventlogtenantPer-user auth events
tenant_extensionsiam_tenant_extensiontenantThe tenant’s own schema overlay rows
tenantiam_tenantcontrolThe tenant registry
tenant_eventlogiam_tenant_eventlogcontrolTenant-level events
superadminiam_staffcontrolThe operator roster
superadmin_grantiam_staff_grantcontrolOperator to tenant grants

Every table carries the iam_ prefix. Entity names are unchanged: they are what the REST path and the access rules reference, and the prefix is on the storage underneath them. It exists because the database schema encodes tenancy rather than the service, so two services sharing a database would otherwise contend for names as ordinary as tenant and role.

The audit side table of an entity follows its table, so users audits to iam_principal_user_audit.

principal records that an id exists, what kind of principal it is, and which entity holds its detail. It holds no detail itself, so a product still brings its own population and the layering is untouched. It is a registry rather than a base table: resolving what an id is becomes one read instead of probing every derived entity in turn.

status on it is where a principal is enabled or locked.

credentials is every way a principal authenticates, local and federated alike, because that is one question with one answer shape. A principal with a password, TOTP and two identity providers is four rows, and “what can this principal log in with” is one query.

challenges is in-flight authentication state of every kind in one entity, rather than one table per flow.

There is no realm entity: realms are configuration, not rows. There is no product entity either. The product is a segment of the tenant key, not a stored object.

Two traits are applied to every entity in the schema, whether or not the entity declares inherits: kisai.common.

ColumnTypeNullableBehaviour
createdbystringnoImmutable after create; defaults to the request’s user id
createdondatetimenoImmutable after create; defaults to the current timestamp
updatedbystringyesMaterialized-computed from the request’s user id on every write
updatedondatetimeyesMaterialized-computed timestamp on every write
deletedbystringyesWrite-once
deletedondatetimeyesWrite-once

Because deletedon exists everywhere, DELETE is a soft delete on every IAM entity, an UPDATE that stamps deletedon and deletedby. Hard removal requires the purge permission.

TypeColumn
klidchar(27). One uppercase prefix letter plus a 26-character ULID
ulid26-character ULID
stringvarchar(255)
textUnbounded text
boolean, int, timestamp, datetime, bytesThe obvious mappings
objectJSONB
array(string)Text array
named enumA declared enum type (sessionstatus)

ID prefixes on klid columns: U user and operator · A agent · B bot · D delegation · G grant.

The registry. One row per principal of any kind, recording that the id exists, what kind it is, and which entity holds the detail.

FieldType
idklidrequired
ptypstringrequired. The principal kind: user, agent, bot, service
realmstringrequired
entitystringrequired. Which entity holds this principal’s detail
display_namestringnullable
statusstringrequired, defaults to active
created_byklidnullable

It holds no detail of its own, so a product still brings its own population and the layering is untouched. Resolving what an id is becomes one read rather than probing each derived entity.

Every way a principal authenticates, local and federated alike. A principal with a password, TOTP and two identity providers is four rows.

FieldType
idklidrequired
principal_idklidrequired
kindstringrequired. password, totp, oidc, webauthn
provider_idstringrequired
subjectstringnullable. The provider’s own identifier
material_refstringnullable. Where the secret lives, never the secret
counterintegernullable
email_at_linkstringnullable. The address at the time the credential was linked
linked_on, last_used_attimestampnullable
activeboolean

Unique on the provider and subject pair, so one federated identity cannot be linked twice.

A grant from one principal to another, including delegation. Each app connection has one: the user as grantor_id and acting_for, the agent as grantee_id, the roles its scopes confer in roles, the scope names in conditions.app_scopes, and the connection’s expiry. Revoking the connection sets revokedon, revoked_by and active: false; the row stays.

FieldType
idklidrequired
grantor_id, grantee_idklidrequired
acting_forklidrequired
acting_for_ptypstringrequired
rolesarray(string)required
tenant_idstringrequired
expiresontimestamprequired
conditionsobjectnullable
spawn_subordinatebooleanWhether the grantee may grant onward
reasonstringnullable
revokedon, revoked_bynullable
activeboolean

In-flight authentication state of every kind, in one entity rather than one table per flow.

FieldType
idklidrequired
kindstringrequired. Which flow this challenge belongs to
provider, subject_ref, realmstringnullable
secret_hashstringnullable
payloadobjectnullable
expiresontimestamprequired
consumedontimestampnullable. Set when the challenge is spent
attemptsinteger

Indexed for lookup and for expiry, so the sweep of spent and expired rows is a range scan.

Actors seen from another plane, with the block list that governs them.

FieldType
idklidrequired
planestringrequired
actor_substringrequired
display_hintstringnullable
first_seen, last_seentimestampnullable
blockedboolean
blocked_reasonstringnullable
blocked_byklidnullable

Unique on the plane and actor pair.

Who belongs to a bot.

FieldType
idklidrequired
bot_idklidrequired
member_idklidrequired
member_ptypstringrequired
granted_byklidrequired
expiresontimestampnullable
conditionsobjectnullable
activeboolean

Identity-provider endpoints and settings.

FieldType
idklidrequired
providerstringrequired, unique
issuer, auth_url, token_url, jwks_url, userinfo_urlstringnullable
client_idstringnullable
client_secret_refstringnullable. A reference to the secret, never the secret
scopesarray(string)nullable
email_claim, subject_claimstringnullable
last_used_attimestampnullable
activeboolean

Service principals.

FieldType
idklidrequired
namestringrequired
spiffe_idstringnullable
displaynamestringnullable
properties, attributesobjectnullable
activeboolean

The base identity entity. access-lock: [actions, rls], scd: { strategy: typeaudit }, not final. This is the entity a product extends.

FieldTypeConstraintsDefault / notes
idklidrequired, unique, immutable'U'+ulid()
emailstringrequired, unique, length 3–255Login identifier and the default one; kept out of logs
mobilestringuniqueLogin identifier; not required; kept out of logs
metaobject—{}
propertiesobject—{}: properties.roles is where authorization roles live
firstnamestringrequired, length 3–255Kept out of logs
lastnamestringrequired, length 3–255Kept out of logs
middlenamestringlength ≤ 255Kept out of logs
displaynamestringcomputedfirstname + " " + lastname
passwordstring—argon2id-hashed on write; redacted on every read
activebooleanrequiredtrue
lockedboolean—false
avatarstring——
tagsarray(string)——
allow_impersonationboolean—false. The tenant’s per-user impersonation consent

allow_impersonation lives in tenant data on purpose: creating or updating a users row requires the admin or iam-service role, and an operator token carries neither, so an operator structurally cannot grant themselves consent.

The operator roster. final: true, scope: customer, scd: { strategy: typeaudit }. Same shape as users minus allow_impersonation, with one difference in the computed name.

FieldTypeConstraintsDefault / notes
idklidrequired, unique, immutable'U'+ulid()
emailstringrequired, unique, length 3–255Login identifier and the default one
mobilestringuniqueLogin identifier
meta, propertiesobject—{}: properties.roles holds the operator’s roles
firstname, lastnamestringrequired, length 3–255—
middlenamestringlength ≤ 255—
displaynamestringcomputedfirstname + " " + middlename + " " + lastname
passwordstring—argon2id-hashed, redacted
activebooleanrequiredtrue
lockedboolean—false
avatarstring——
tagsarray(string)——

Only iam-service may unmask an operator’s password hash. An operator-admin can manage the roster but never read another operator’s credential.

Agent principals. Each is the agent of an app connection, acting for one user under one principal_grant. final: true with scd: { strategy: typeaudit }. The user an agent acts for may read it; every write requires admin or iam-service.

FieldType
idklid'A'+ulid()
acting_forklidrequired, immutable. The user the agent acts for
acting_for_ptypstringrequired, immutable
grant_idklidrequired, immutable. The grant that confers its authority
expiresontimestamprequired
displaynamestringnullable, up to 200. The connection’s name
tool_allowlistarray(string)nullable. The tools of the connection’s scopes
model_policyobjectnullable
attributesobjectnullable. App connections record app.kind and the user’s app.realm
activebooleandefault true; false once the connection is revoked

Non-human principals and delegation records. Both are final: true with scd: { strategy: typeaudit }, and both carry claims, which is why every action requires admin or iam-service. They are records of the principals you manage; issue credentials through the documented auth flows.

Fieldiambotsiamdelegations
idklid 'B'+ulid()klid 'D'+ulid()
namestring, required, 3–255, unique index with deletedon. no unique validation—
displaynamestring ≤ 1024—
useridklid, requiredklid, required
touserid—klid, required
notbefore / notafterabsenttimestamp, required
activeboolean, requiredboolean, required
attributesobject {}array(string)
claimsobject {}object {}
allowedservicesarray(string)—

Setting realmconfig.enable.agents, .bots or .delegations to false removes the entity from that tenant’s composed schema entirely, the table ceases to exist for the tenant, rather than the routes being guarded.

The live impersonation path is POST /superadmin/impersonate; it does not consult iamdelegations. See Impersonation.

Every entity in this section is final: true and restricted to the iam-service role on all four actions. No external token can carry that role, so none of these tables are reachable over the REST or admin surface.

FieldTypeNullableNotes
idulidnoulid(); the row id used to revoke
session_idstringnoUnique. The opaque bearer credential, ≥128-bit CSPRNG
principal_idstringno—
ceptstringnoServer-set; never client-asserted
statussessionstatusnoactive | revoked | expired, default active
aalintnoDefault 1
auth_methodstringno—
idp_issstringyesIdP issuer, for logout correlation
idp_sidstringyesIdP session id
user_agent_labelstringno—
created_attimestampno—
last_seen_attimestampno—
idle_timeout_sintnoDefault 0
absolute_expirytimestampno—
revoked_reasonstringyesuser_logout | admin_revoke | concurrent_evict | backchannel_logout | idle_expired | absolute_expired | rotated
realmstringyes—
impersonator_idstringyesSet only on an impersonated session
impersonator_reasonstringyesLength ≤ 500
impersonator_modestringyesreadonly | readwrite

Indexes: session_session_id_uq unique on (session_id), session_principal_idx on (principal_id), session_idp_idx on (idp_iss, idp_sid).

Rows are written only on a tenant whose session preset resolves to the managed model; see Sessions.

FieldTypeNullableNotes
idulidno—
useridklidno—
authtypestringnoLength ≤ 255
tokenstringno—
tenantstringnoThe full tenant key; cross-checked at redeem
realmstringno—
familystringnoRotation family id; empty on rows written before rotation existed
rotatedbooleannoDefault false. The tombstone that drives reuse detection
expiresontimestampyes—

Replaying a token whose rotated flag is set revokes the whole family.

FieldTypeNotes
idulid—
servicestringrequired, ≤ 255. An API key belongs to a service; an app key carries kisai-app
keybytesrequired. A placeholder written to satisfy NOT NULL, not used
secretstringrequired, encrypted at rest under the secret key; stores the SHA-256 of the plaintext
capabilitiesobject{}
expiresattimestamprequired
principal_idklidnullable, immutable. Set on an app key: the agent of its app connection
namestringnullable, up to 200. An app key’s connection name
lastusedontimestampnullable. An app key’s latest successful exchange

The wire format handed to the caller once at issue time is <id>.<secret>, and kisak_<id>.<secret> for an app key.

FieldTypeNotes
idulid—
namestringrequired, ≤ 255
useridklidrequired
providerstringrequired, ≤ 255
secretstringencrypted at rest under the secret key
counterint—
lastusedtimestampDoubles as the enabled flag: unset means pending setup, set means active
realmstringrequired
FieldTypeNotes
idulid—
useridklidrequired
providerstringrequired, ≤ 255
tokenstringrequired
expiresattimestamprequired
approvedbooleanrequired, default false
numbersobject{}
realmstringrequired
FieldTypeNotes
idulid—
tenantslugstringrequired, ≤ 50
emailstringrequired, ≤ 255
codestringrequired, ≤ 255: stores a hash of the emailed code
expiresontimestamprequired
usedontimestampStamped on confirm

There is no userid column; the row is keyed by email + tenantslug, a row whose expireson is missing or not a time is treated as expired.

FieldTypeNotes
idulid—
statekeystringrequired
statevaluestringrequired
codeverifierstringThe PKCE verifier; kept out of logs
expiresontimestamp—

Server-side only, single-use, short-lived. No OAuth provider is wired in the deployable binary, so nothing writes these rows in a shipped deployment.

EntityFieldTypeNotes
webauthn_credentialidulid—
useridklidrequired
namestringrequired, ≤ 255. The user’s label for the authenticator
credential_idbytesrequired. The opaque WebAuthn credential id
credentialobjectrequired. The full marshaled credential as JSON
realmstringrequired: carried for operational queries only
webauthn_sessionidulid—
namestringrequired. The register flow encodes the label as register:<name>
dataobjectrequired. The in-flight challenge, purged after finish

A user may hold many credential rows, the JSON envelope absorbs library changes without a schema migration. WebAuthn is not enabled in the deployable binary; every route answers 503 webauthn_disabled, so these tables stay empty in a shipped deployment. See Passwordless.

FieldTypeNotes
idulid—
kidstringrequired, unique, ≤ 64
algstringrequired, enum EdDSA | ES256
publickeytextrequired
privatekeytextrequired; kept out of logs, excluded from export, encrypted at rest
activebooleanDefault true

At most one active row per tenant. Rotation flips the previous row to active: false in the same transaction that inserts the new one; inactive rows are retained so previously issued tokens keep verifying. Cloned into the control plane so operator tokens are signed by a keyring no tenant shares.

final: true, scd: { strategy: typeaudit }. Mounted for admin CRUD.

FieldTypeConstraints
idulidrequired, unique, immutable
slugstringrequired, unique
displaynamestringrequired
activebooleanrequired, default true
propertiesobject{}

The registry. final: true, scope: customer, scd: { strategy: typeaudit }.

FieldTypeNullableConstraints
idulidnorequired, unique, immutable: ulid()
parentidulidyes—
slugstringnorequired, unique, ≤ 50. The tenant key
displaynamestringnorequired, ≤ 255
namespacestringyes—
domainstringyes—
activebooleannorequired, default true
markedforseedbooleannoSet on register, cleared when provisioning completes
metaobjectno{}

Row-level read: ("iam-service" in user.roles || "root" in user.roles) ? "" : user.grants. An operator sees only the tenants they hold a grant for; an operator with no grants gets a filter matching no row, so unauthorized tenants are invisible rather than merely unactionable. user.grants is bound per request from the plane’s superadmin_grant rows, so a revoke takes effect immediately.

FieldTypeNullableConstraints
idklidnorequired, unique, immutable: 'G'+ulid()
superadmin_idstringnorequired, immutable
tenant_idstringnorequired, immutable. The registry row id, not the tenant key
reasonstringyes≤ 500
activebooleannoDefault true

Indexes: superadmin_grant_uq unique on (superadmin_id, tenant_id), superadmin_grant_operator_idx on (superadmin_id).

The row is deliberately flat. No role column. superadmin_id and tenant_id are immutable: a grant cannot be moved, only revoked and re-granted. An operator holding root needs no rows; the role is an implicit grant over every tenant in its own plane. See The operator plane.

The tenant’s own schema-overlay store. final: true.

FieldTypeNullableConstraints
idulidnorequired, unique, immutable
pathstringnorequired, unique. One overlay row per path
content_typestringyesMIME type; application/x-yaml, application/yaml, text/yaml and text/x-yaml are read as schema overlays
content_texttextyes—
content_blobbytesyes—

Sixteen entities declare scd: { strategy: typeaudit }: users, role, tenant, superadmin, superadmin_grant, principal, principal_grant, credentials, iamagents, iambots, iamdelegations, iamservices, bot_member, peer_actors, impersonation_requests and providerconfigs. Each gets a parallel table with one row per field change.

ColumnTypeNotes
idTEXT PRIMARY KEYAudit row ULID
entity_idTEXT NOT NULLLogical id of the changed row
field_nameTEXTEmpty for a delete
old_valueTEXTJSON-encoded pre-change value
new_valueTEXTJSON-encoded post-change value
operationTEXT NOT NULLcreate | update | delete
changed_atTIMESTAMPTZ NOT NULLDefaults to now()
changed_byTEXTThe identity the change was performed under. The target user during an impersonation; empty for system writes
actorTEXTWho performed it. The operator during an impersonation, otherwise the same as changed_by

During an impersonation changed_by is the target user and actor is the operator, and the rows land in the tenant’s own schema so the customer can query them. session, api_key, user_refresh_token and jwt_signing_key have no audit table.

These look like the audit stores and are never written by the service. The real record is the _audit side tables above.

EntityFields
user_eventlogid (ulid), userid (string), eventtype / attributetype / outcometype (int), message (string), context (object {}), meta (object {}), realm (string, required)
tenant_eventlogid (ulid), tenantid (ulid, required), eventtype / attributetype / outcometype (int), message (string), context (object {})

Both restrict create, update and delete to iam-service: an administrator can read the log but cannot forge or erase entries. tenant_eventlog read additionally admits tenant-read and tenant-provision.

Every entity is deny-by-default, an action with no rule is refused. Rules are expr predicates over user.roles, user.id and user.grants.

Entityreadcreateupdatedeleteunmask
usersuser.id != ""admin, iam-serviceadmin, iam-serviceadmin, iam-serviceiam-service
role, iambots, iamdelegations, peer_actorsadmin, iam-serviceadmin, iam-serviceadmin, iam-serviceadmin, iam-service—
iamagentsadmin, iam-service, the user it acts foradmin, iam-serviceadmin, iam-serviceadmin, iam-service—
principaladmin, iam-service, the principal itselfadmin, iam-serviceadmin, iam-serviceadmin, iam-service—
principal_grantadmin, iam-service, grant-readadmin, iam-serviceadmin, iam-serviceadmin, iam-service—
user_eventlogadmin, iam-serviceiam-serviceiam-serviceiam-service—
session, user_refresh_token, challenges, user_mfa_request, user_magic_link, password_reset_request, oauthstate, webauthn_credential, webauthn_session, api_key, jwt_signing_key, tenant_extensions, credentialsiam-serviceiam-serviceiam-serviceiam-service—
tenantiam-service, root, tenant-read, tenant-provisioniam-service, root, tenant-provisioniam-service, root, tenant-provisioniam-service, root—
tenant_eventlogiam-service, root, tenant-read, tenant-provisioniam-serviceiam-serviceiam-service—
superadminiam-service, root, superadmin-adminiam-service, root, superadmin-adminiam-service, root, superadmin-adminiam-service, rootiam-service
superadmin_grantiam-service, root, superadmin-admin, tenant-read, tenant-provisioniam-service, root, superadmin-adminiam-service, root, superadmin-adminiam-service, root, superadmin-admin—

Two entities declare row-level security:

EntityRuleEffect
users("admin" in user.roles || "iam-service" in user.roles) ? "" : user.idA non-admin reads only their own row
tenant("iam-service" in user.roles || "root" in user.roles) ? "" : user.grantsAn operator reads only granted tenants

An RLS rule returns a value, not SQL: an empty string means unrestricted, a scalar becomes an equality filter on the key column, a list becomes an IN predicate.

iam-service is the service’s own internal principal, a context-attached identity whose user id and single role are both the literal iam-service. Every internal credential read and write runs under it, which is why the credential tables can be sealed to it. It is not a role any issued token can carry, and there is no engine-level system bypass behind it. See Authorization for the role vocabulary and how properties.roles reaches a request.

The schema a tenant runs is folded from three layers, in order:

LayerSourceMay contribute
Service baseThe embedded entity definitions, parsed once per process—
ProductThe product’s iam/ folder, delivered through the product configuration sourceNew entities, new fields on non-final entities, access tiers not named in access-lock:
TenantRows in tenant_extensionsNew entities and new fields only. An access block from this layer is dropped

The control plane takes neither layer: a tenant never reshapes the plane that governs it.

SealMeaningEntities
final: trueNo layer may contribute anything. No fields, no accessEvery entity in the inventory except users
access-lock: [actions, rls]A product may add fields and override the services and fields access tiers, but not actions or rlsusers
access-lock: [actions]A product may add fields and override every tier except actionsuser_eventlog

The four valid access tiers are services, actions, rls and fields.

Re-declare the entity by name in a layer file, listing only the new fields:

entities:
- name: users
fields:
- name: department
type: string
nullable: true
- name: employee_number
type: string
nullable: true

Place it in the product’s iam/extend/ folder, or store it as a tenant_extensions row with content_type: application/x-yaml. The fold adds each new field name to the base entity and tags it with the contributing layer.

The fold never fails. A structural collision, a tenant-supplied access block, a scope change, a contribution to a final entity, or a duplicate field name is discarded, recorded as a diagnostic and logged at error level, the base definition stands and the engine keeps serving.

DiagnosticCause
override-appliedA layer legitimately replaced a value
ignored-duplicateThe field name already exists on the base
ignored-tenant-accessA tenant layer supplied an access: block
ignored-locked-tierA product tried to override an access-lock tier
ignored-final-entityA layer contributed to a final entity
ignored-scope-changeA layer tried to move an entity to another plane
ignored-shadowA layer redefined a base type or enum

The layer’s author sees a log line, not a failed deploy, and the field simply does not exist.

Login identifiers are declared on the field

Section titled “Login identifiers are declared on the field”

Any field carrying attributes: {useforauth: true} becomes a login-identifier column; useforidentity: true marks the default one, tried first. Base users declares email with both and mobile with useforauth. A product adds its own on users or on its realm’s identity entity.

entities:
- name: users
fields:
- name: employee_number
type: string
nullable: true
attributes:
useforauth: true

An entity declaring none falls back to email. A login request naming an identity type the entity did not mark is refused with 400 bad_identity_type and the declared list in the message. The service never filters on an unmarked column. Which entity a login authenticates against is a realm decision: see Realms.

ExpectedReality
An invitation entity or invite flowNot implemented. No entity, no route, no code
Email or phone verificationNot implemented
Self-service registrationNo signup route in the deployable service
A user-to-role join tableNone; roles live in users.properties.roles
A realm entityRemoved: realms are configuration, not rows
A product entityThe product is a segment of the tenant key, not a row

Accounts are created by exactly four paths: admin CRUD (POST /admin/user or POST /rest/users), the seed command, tenant provisioning, and just-in-time on an OAuth callback for an unknown email. Signup events fire only from that last path, which no shipped deployment reaches, no OAuth provider is wired in the deployable binary. Seeding and tenant provisioning are covered in Operating.

For the routes that read and write these entities, see the IAM API reference and the error table. For the entity engine itself, query syntax, hooks, migrations and the generic REST surface, see the Data.