Events
An event records something that happened in QAuth: a sign-in, a refused token request, a new client. Events exist so that automation outside QAuth can act on them (ADR-018 §3). ADR-018 names four routes for them: signed webhooks in the Standard Webhooks format, a cursor-based event API, Shared Signals Framework streams, and OpenTelemetry export. Every route carries the same event, in the envelope below. The event types and their payload schemas are part of the 1.0 stability contract (ADR-018 §5).
This page is generated from the type registry in libs/shared/events, together with the JSON
Schema files it links.
The envelope
Section titled “The envelope”Every event has these members. type, category and data depend on the type; the
others mean the same for every type. A member that does not apply is absent, never null.
{ "id": "0199f2b4-7c3e-7a51-9d2b-3a6c8e1f0a42", "type": "urn:qauth:event:user.signed_in:v1-rc.0", "time": "2026-10-22T09:30:00.123Z", "realm": "0199f2b4-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "category": "user", "actor": { "type": "user", "id": "0199f2b4-2b3c-7d4e-9f5a-6b7c8d9e0f1a" }, "subject": { "type": "user", "id": "0199f2b4-2b3c-7d4e-9f5a-6b7c8d9e0f1a" }, "client": { "id": "notes-app" }, "request": { "traceId": "req-7f3a", "ip": "203.0.113.7", "userAgent": "Mozilla/5.0" }, "data": { "method": "password" }}| Member | Type | Required | Meaning |
|---|---|---|---|
id | UUID | yes | The event id, a UUIDv7. One event keeps one id on every route and every retry, so a receiver drops duplicates by it. It is the webhook-id of a webhook and the source of an SSF jti. |
type | string | yes | The event type, urn:qauth:event:<name>:v<N>, or :v<N>-rc.<M> for a release candidate. The registry lists every type. |
time | time (RFC 3339, UTC) | yes | When the event happened, as an RFC 3339 time in UTC. Not when it was delivered. |
realm | UUID | yes | The id of the realm the event happened in. |
category | one of user, admin | yes | user: an end user’s own activity. admin: an administrator’s change. Fixed by the type. |
actor | object | no | Who or what caused the event. |
actor.type | one of user, client, system, operator_cli, or a later value | yes | user: a person, signed in. client: an OAuth client acting for itself or, with delegationChain, as an agent for the subject. system: QAuth itself, such as a scheduled job. operator_cli: an operator on the server host, through a QAuth command-line tool. |
actor.id | string | no | The actor’s identifier: a user id, a client’s client_id, or the operating-system user for operator_cli. Absent for system. |
actor.delegationChain | array of string | no | The RFC 8693 act chain of a delegated request, as client_id values: the acting agent first, then each earlier actor. Absent when nothing was delegated. |
subject | object | no | What the event is about. |
subject.type | one of user, client, api_key, ssf_stream, or a later value | yes | What kind of thing the subject is. |
subject.id | string | yes | The subject’s identifier: a user id, a client’s client_id, an API key id or a Shared Signals Framework stream_id. It stays valid after the subject is deleted. |
client | object | no | The OAuth client the request came through. |
client.id | string | yes | The client’s client_id. |
request | object | no | The HTTP request that caused the event. |
request.traceId | string | no | The id under which QAuth logged the request: the trace_id of a problem document from the same request. |
request.ip | IPv4 address or IPv6 address | no | The end user’s IP address, as QAuth derived it from the request. An IPv4-mapped IPv6 address is written in its IPv4 form. |
request.userAgent | string | no | The User-Agent header, cut to 1024 characters. |
data | object | yes | The type’s own payload. Its schema is the type’s. |
- The
idis a UUIDv7, assigned once when the event is recorded. A retry, a redelivery and every route repeat it, so a receiver drops duplicates by it. A webhook’swebhook-idheader is the event id, and an SSF Security Event Token’sjtiis derived from it. - The
subjectis a plain id with no database link: it stays valid after the user or the client is deleted. - A webhook body is the envelope. Standard Webhooks recommends a full-stop delimited
type, atimestampanddata: the short name in the middle of the identifier is the delimited type, andtimeis the timestamp. - The envelope’s schema is envelope.json.
Payload rules
Section titled “Payload rules”These rules hold for every event’s data. They were written for the audit log
(ADR-011 §8,
ADR-017 §11) and apply to events.
- Ids, not names or addresses.
datanames a user, a client or a record by its id. A type that needs a name, an email address, a phone number or an IP address declares that field in its registry entry. No type registered today does. - Never a secret. No password, code, OTP, token, key, assertion, signature, cookie, secret,
or set-up or reset link, in any form. There is no exception. An admin event’s diff shows a
changed resource’s own fields; there a secret field holds
***, never its value. - Hidden identifiers are keyed HMACs. An identifier that must not be revealed, such as the address a failed sign-in typed, is carried as an HMAC under a server-side key, never as the value and never as a plain hash.
A scanner enforces the rules. The registry’s tests fail when a type’s schema declares a field
named like a secret, or like personal data the type has not declared. parseEvent, the check a
single event passes before it is stored or sent, applies them again: a field named like a secret,
or a value shaped like a token or a key, refuses the event. The scanner reads names, so a field that holds an
id, a type or a count of such a thing passes when its name ends in Id, Type or Count
(apiKeyId, issuedTokenType).
Admin events
Section titled “Admin events”An admin event records a change an administrator, a service account or an operator made (ADR-020 §3, ADR-019 Decision 7). Admin events are always on: no environment key and no realm setting turns them off. Each is written in the transaction of the change it records, so the change and its event commit together.
The diff. data.diff lists what the operation changed, one entry per field:
pathnames the field, as a JSON Pointer (RFC 6901) into the changed resource, such as/smtp/host.beforeandafterhold its value.beforeis absent when the field did not exist, andafterwhen it no longer does;nullmeans the field heldnull.- Only changed fields are listed. A nested object present on both sides is diffed member by member. Any other value, an array included, is shown whole.
[ { "path": "/displayName", "before": "Notes", "after": "Team notes" }, { "path": "/smtp/password", "before": "***", "after": "***" }, { "path": "/allowedScopes", "before": ["openid"], "after": ["openid", "profile"] }]Masking. A secret field holds *** on both sides, whatever its value. A field is secret
when the operation marks it, or when its name holds a secret, marked or not: a password, pass,
PIN, secret, token, key, salt, pepper, cookie, signature, credential, auth or connection string,
a key-encryption or data-encryption key (kek, dek), a set-up, reset or other one-time link,
or a one-time password’s link (totpUri). A name whose last word only describes the secret is
shown: accessTokenTtl, tokenEndpointAuthMethod, signingKeyId, jwksUri, keyUse,
saltRounds, authServer. So is a code or a key that only names something: countryCode,
attrKey. A changed secret is still listed, so a rotation shows as *** to ***. A flag
(true or false) is never masked.
A value shaped like a secret is masked wherever it sits: a token, a signed or encrypted object, a
PEM block, an Authorization header value, a private or symmetric JWK, or a URL that carries a
credential: one with a password (or, over HTTP, a user name), a query or fragment member named like
a secret (?access_token=, ?sig=, ?key=, ?code=), an otpauth:// URI, or a webhook URL
that holds its secret in the path. A public JWK is shown, and a list of keys shows its public keys
with each private one masked. A member name shaped like a secret refuses the event.
The field names in a diff are the resource’s own, so the payload scanner reads a diff’s values,
not its names, and checks instead that every field named like a secret holds ***. A diff may
show personal data, such as a contact address an admin changed: admin events are read by the
realm’s admins.
Approvals. data.approvals lists the approvals the operation ran on: both approvals of a
two-admin operation, each with the approver, the passkey credential it was given with, and who
created the approver’s account.
The hash chain. The event store chains a realm’s admin events: each stores the hash of the one
before it, and its own hash is SHA-256 over the chain format’s id (qauth-event-chain/1-rc.0,
a release candidate until 1.0.0), that hash, the id of the transaction that wrote the event, and
the event’s canonical JSON (RFC 8785). A changed event breaks the chain at that event,
and a removed one at the event after it. The chain’s hashes are stored beside the event and are
not part of the envelope.
Versioning
Section titled “Versioning”An event type’s identifier is urn:qauth:event:<name>:v<N>. The <name> is its short
name: lower-case snake_case segments joined by full stops, the resource first. <N> is the
major version of its data. Every QAuth-defined identifier carries a version (ADR-018 §5).
Release candidates. Until QAuth 1.0.0, every type is a release candidate and its identifier
ends in -rc.<M>, as in urn:qauth:event:user.signed_in:v1-rc.0. Nothing about a candidate
is promised. A breaking change before 1.0.0 raises <M> (:v1-rc.0 becomes :v1-rc.1), so
an identifier never names two different schemas. The release that ships QAuth 1.0.0 drops the
suffix from every type: :v1 is the version under the stability promise, and the rules below
apply from then on.
Within a major release, the contract changes only by addition:
- a new type, which is a new entry in the registry;
- a new optional member of a type’s
data, or of the envelope; - a new value of an open set (
x-extensible-enum, shown on this page as “or a later value”).
Anything else is a breaking change: removing or renaming a member, changing its type, making a
member required, adding a required member, or narrowing what a member accepts. A breaking change
makes a new type with the next version, such as :v2. QAuth emits both versions for every
event until the deprecation window ends, so a receiver moves at its own pace. The old type is
marked deprecated and names its replacement. It is removed only in a new major release, no sooner
than 12 months after the deprecation (ADR-018 §5).
A receiver ignores members it does not know, and accepts a value of an open set it does not know.
The published schemas leave objects open for that reason. A closed set, such as category, does
not grow within a major release.
The stable-surface check compares each schema file with the last release and fails on a breaking change that no one approved.
Schemas
Section titled “Schemas”Each type has a JSON Schema (draft 2020-12) of its whole event: the envelope, with type,
category and data fixed to the type. They are served under /schemas/events/, and each
file’s $id is its URL. The envelope’s own schema accepts an event of any type.
Event types
Section titled “Event types”user.signed_in v1-rc.0
Section titled “user.signed_in v1-rc.0”A person signed in: the credential checked out and QAuth started a browser session or issued tokens.
- Identifier:
urn:qauth:event:user.signed_in:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: user.signed_in.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
method | one of password, wallet, or a later value | yes | password: an identifier and a password. wallet: a credential presented from a wallet (OpenID4VP). The set may grow in a minor release. |
verifierProfile | string | no | The verifier profile the wallet presentation was checked under, such as haip-1.0. |
user.sign_in_failed v1-rc.0
Section titled “user.sign_in_failed v1-rc.0”A sign-in was refused: an unknown identifier, a wrong credential, a locked or disabled account.
- Identifier:
urn:qauth:event:user.sign_in_failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject:
user, when known - Schema: user.sign_in_failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
method | one of password, wallet, or a later value | yes | password: an identifier and a password. wallet: a credential presented from a wallet (OpenID4VP). The set may grow in a minor release. |
reason | string | yes | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
identifierHmac | string | no | A keyed HMAC (HMAC-SHA-256, base64url) of the identifier the person typed, so repeated attempts at one identifier can be correlated without revealing it. Absent when the attempt named a known user, who is then the subject. |
verifierProfile | string | no | The verifier profile the wallet presentation was checked under, such as haip-1.0. |
user.signed_out v1-rc.0
Section titled “user.signed_out v1-rc.0”A person signed out, and QAuth ended their sessions.
- Identifier:
urn:qauth:event:user.signed_out:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: user.signed_out.v1-rc.0.json
data has no members: the envelope carries the event.
user.sign_out_failed v1-rc.0
Section titled “user.sign_out_failed v1-rc.0”A sign-out request was refused or could not complete.
- Identifier:
urn:qauth:event:user.sign_out_failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject:
user, when known - Schema: user.sign_out_failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
reason | string | yes | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
user.registered v1-rc.0
Section titled “user.registered v1-rc.0”A person created an account.
- Identifier:
urn:qauth:event:user.registered:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: user.registered.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
method | one of password, wallet, or a later value | yes | password: an identifier and a password. wallet: a credential presented from a wallet (OpenID4VP). The set may grow in a minor release. |
user.registration_failed v1-rc.0
Section titled “user.registration_failed v1-rc.0”An account could not be created, for example because the address is in use.
- Identifier:
urn:qauth:event:user.registration_failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject: none: the event never carries one
- Schema: user.registration_failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
reason | string | yes | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
identifierHmac | string | no | A keyed HMAC (HMAC-SHA-256, base64url) of the identifier the person typed, so repeated attempts at one identifier can be correlated without revealing it. Absent when the attempt named a known user, who is then the subject. |
authorization.completed v1-rc.0
Section titled “authorization.completed v1-rc.0”The authorization endpoint sent the client back with an authorization response that grants access.
- Identifier:
urn:qauth:event:authorization.completed:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: authorization.completed.v1-rc.0.json
data has no members: the envelope carries the event.
authorization.failed v1-rc.0
Section titled “authorization.failed v1-rc.0”The authorization endpoint refused a request: an unknown client, a redirect URI that is not registered, a scope the client may not have, or a denial.
- Identifier:
urn:qauth:event:authorization.failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject:
user, when known - Schema: authorization.failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
error | string | yes | The OAuth or OpenID Connect error code the request was refused with, such as invalid_grant. |
reason | string | no | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
step_up.required v1-rc.0
Section titled “step_up.required v1-rc.0”A request needs a fresh sign-in or new consent before it can go on, for example for a dangerous scope (ADR-007 §2).
- Identifier:
urn:qauth:event:step_up.required:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: step_up.required.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
reason | string | yes | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
error | string | no | The OAuth or OpenID Connect error code the request was refused with, such as invalid_grant. |
elevatedScopes | array of string | no | The scopes the request adds to what the user already granted. |
dangerousScopes | array of string | no | The requested scopes classed as dangerous. |
prompt | string | no | The OpenID Connect prompt value of the request. |
maxAge | integer | no | The max_age of the request, in seconds. |
step_up.elevated v1-rc.0
Section titled “step_up.elevated v1-rc.0”After a fresh sign-in, a user granted a client dangerous scopes (ADR-007 §2).
- Identifier:
urn:qauth:event:step_up.elevated:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: step_up.elevated.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
scopes | array of string | yes | Every scope granted. |
dangerousScopes | array of string | yes | The granted scopes classed as dangerous. |
scopeMode | one of readonly, admin, exec, or a later value | no | The agent scope mode (ADR-007 §2) the request was granted: readonly, admin or exec. |
authenticatedAt | time (RFC 3339, UTC) | no | When the fresh sign-in happened, as an RFC 3339 time in UTC. |
consent.granted v1-rc.0
Section titled “consent.granted v1-rc.0”A user granted a client the scopes it asked for.
- Identifier:
urn:qauth:event:consent.granted:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: consent.granted.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
scopes | array of string | yes | The scopes granted. |
remembered | boolean | yes | Whether the user chose to remember the decision for later requests. |
dangerousScopes | array of string | no | The granted scopes classed as dangerous. |
consent.denied v1-rc.0
Section titled “consent.denied v1-rc.0”Consent was not given: the user declined, or the request did not match what the consent screen showed.
- Identifier:
urn:qauth:event:consent.denied:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: consent.denied.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
error | string | no | The OAuth or OpenID Connect error code the request was refused with, such as invalid_grant. |
reason | string | no | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
consent.revoked v1-rc.0
Section titled “consent.revoked v1-rc.0”A user withdrew a client’s consent. QAuth revoked the refresh tokens the consent covered.
- Identifier:
urn:qauth:event:consent.revoked:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: consent.revoked.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
consentId | UUID | yes | The id of the consent that was withdrawn. |
revokedRefreshCount | integer | no | How many refresh tokens were revoked with it. |
token.issued v1-rc.0
Section titled “token.issued v1-rc.0”The token endpoint issued tokens: for an authorization code, a refresh, client credentials, a token exchange or a JWT bearer assertion.
- Identifier:
urn:qauth:event:token.issued:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: token.issued.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
grantType | string | yes | The grant_type of the token request, such as authorization_code. |
scopes | array of string | no | The scopes of the issued access token. |
audience | array of string | no | The audience of the issued token. |
resources | array of string | no | The RFC 8707 resource indicators the token is bound to. |
expiresIn | integer | no | The lifetime of the issued access token, in seconds. |
issuedTokenType | string | no | The RFC 8693 issued_token_type of a token exchange. |
refreshFamilyId | UUID | no | The refresh family the issued refresh token belongs to. Every rotation keeps it. |
delegationDepth | integer | no | How many actors the RFC 8693 act chain of the issued token holds. |
idJagId | string | no | The jti of the identity assertion authorization grant minted or consumed (ADR-011). Never the grant itself. |
idJagIssuer | string | no | The issuer of a consumed identity assertion authorization grant (ADR-011). |
scopeMode | one of readonly, admin, exec, or a later value | no | The agent scope mode (ADR-007 §2) the request was granted: readonly, admin or exec. |
token.request_failed v1-rc.0
Section titled “token.request_failed v1-rc.0”The token endpoint refused a request: failed client authentication, an invalid or replayed grant, a scope or resource outside what was granted.
- Identifier:
urn:qauth:event:token.request_failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject:
user, when known - Schema: token.request_failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
grantType | string | no | The grant_type of the token request, such as authorization_code. |
error | string | yes | The OAuth or OpenID Connect error code the request was refused with, such as invalid_grant. |
reason | string | no | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
refreshFamilyId | UUID | no | The refresh family a replayed grant (reason code_replay or refresh_replay) had issued, which the refusal revoked. Absent when the grant issued none. |
revokedRefreshCount | integer | no | How many refresh tokens of that family the refusal revoked; 0 when they were revoked already. Present for the reasons code_replay and refresh_replay. |
token.revoked v1-rc.0
Section titled “token.revoked v1-rc.0”A client revoked a token at the RFC 7009 revocation endpoint.
- Identifier:
urn:qauth:event:token.revoked:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: token.revoked.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
typeHint | string | no | The token_type_hint the client sent, such as refresh_token. |
token.revocation_failed v1-rc.0
Section titled “token.revocation_failed v1-rc.0”The revocation endpoint refused a request, for example on failed client authentication.
- Identifier:
urn:qauth:event:token.revocation_failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject: none: the event never carries one
- Schema: token.revocation_failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
error | string | yes | The OAuth or OpenID Connect error code the request was refused with, such as invalid_grant. |
reason | string | no | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
token.introspected v1-rc.0
Section titled “token.introspected v1-rc.0”A resource server introspected an active token (RFC 7662).
- Identifier:
urn:qauth:event:token.introspected:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: token.introspected.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
tokenClientId | string | no | The client_id the introspected token was issued to. |
token.introspection_failed v1-rc.0
Section titled “token.introspection_failed v1-rc.0”An introspection request failed: client authentication, or a token that is invalid, expired, revoked or not one the caller may inspect.
- Identifier:
urn:qauth:event:token.introspection_failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject:
user, when known - Schema: token.introspection_failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
error | string | yes | The OAuth or OpenID Connect error code the request was refused with, such as invalid_grant. |
reason | string | no | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
userinfo.served v1-rc.0
Section titled “userinfo.served v1-rc.0”The userinfo endpoint returned claims for an access token.
- Identifier:
urn:qauth:event:userinfo.served:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: userinfo.served.v1-rc.0.json
data has no members: the envelope carries the event.
userinfo.request_failed v1-rc.0
Section titled “userinfo.request_failed v1-rc.0”The userinfo endpoint refused a request.
- Identifier:
urn:qauth:event:userinfo.request_failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject:
user, when known - Schema: userinfo.request_failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
error | string | yes | The OAuth or OpenID Connect error code the request was refused with, such as invalid_grant. |
reason | string | no | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
client.created v1-rc.0
Section titled “client.created v1-rc.0”An OAuth client was created: by RFC 7591 dynamic registration, or by a developer through the developer API.
- Identifier:
urn:qauth:event:client.created:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
client, when known - Schema: client.created.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
registration | one of dynamic, developer_api, or a later value | yes | dynamic: RFC 7591 dynamic client registration. developer_api: a developer created it. The set may grow in a minor release. |
isPublic | boolean | yes | Whether the client is public, with no client authentication. |
isAgent | boolean | no | Whether the client registered as an agent (ADR-007 §2). |
grantTypes | array of string | yes | The grant types the client may use. |
scopes | array of string | no | The scopes the client may request. |
authMethod | string | no | How the client authenticates at the token endpoint, such as private_key_jwt. |
client.updated v1-rc.0
Section titled “client.updated v1-rc.0”A developer changed a client’s settings.
- Identifier:
urn:qauth:event:client.updated:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
client, when known - Schema: client.updated.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
fields | array of string | yes | The names of the settings that changed. Never their values. |
client.deleted v1-rc.0
Section titled “client.deleted v1-rc.0”A developer deleted a client.
- Identifier:
urn:qauth:event:client.deleted:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
client, when known - Schema: client.deleted.v1-rc.0.json
data has no members: the envelope carries the event.
client.secret_rotated v1-rc.0
Section titled “client.secret_rotated v1-rc.0”A developer replaced a client’s secret. The old secret stopped working.
- Identifier:
urn:qauth:event:client.secret_rotated:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
client, when known - Schema: client.secret_rotated.v1-rc.0.json
data has no members: the envelope carries the event.
client.suspended v1-rc.0
Section titled “client.suspended v1-rc.0”An operator suspended a client: it can no longer obtain tokens until the suspension is lifted.
- Identifier:
urn:qauth:event:client.suspended:v1-rc.0 - Category:
admin· Severity:warning· Since: v0.2.0 - Subject:
client, when known - Schema: client.suspended.v1-rc.0.json
data has no members: the envelope carries the event.
client.suspension_lifted v1-rc.0
Section titled “client.suspension_lifted v1-rc.0”An operator lifted a client’s suspension.
- Identifier:
urn:qauth:event:client.suspension_lifted:v1-rc.0 - Category:
admin· Severity:info· Since: v0.2.0 - Subject:
client, when known - Schema: client.suspension_lifted.v1-rc.0.json
data has no members: the envelope carries the event.
api_key.created v1-rc.0
Section titled “api_key.created v1-rc.0”A developer created an API key for a client.
- Identifier:
urn:qauth:event:api_key.created:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
api_key, when known - Schema: api_key.created.v1-rc.0.json
data has no members: the envelope carries the event.
api_key.revoked v1-rc.0
Section titled “api_key.revoked v1-rc.0”A developer revoked an API key. It stopped working.
- Identifier:
urn:qauth:event:api_key.revoked:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
api_key, when known - Schema: api_key.revoked.v1-rc.0.json
data has no members: the envelope carries the event.
wallet.linked v1-rc.0
Section titled “wallet.linked v1-rc.0”A signed-in user linked a wallet credential to their account.
- Identifier:
urn:qauth:event:wallet.linked:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
user, when known - Schema: wallet.linked.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
credentialId | string | yes | The id of the account credential the wallet was linked as. |
subjectSource | string | yes | How the subject was resolved from the presentation (ADR-009). |
rebound | boolean | yes | Whether the link replaced an earlier binding of the same credential. |
verifierProfile | string | yes | The verifier profile the wallet presentation was checked under, such as haip-1.0. |
wallet.link_failed v1-rc.0
Section titled “wallet.link_failed v1-rc.0”A wallet could not be linked, for example because it is linked to another account.
- Identifier:
urn:qauth:event:wallet.link_failed:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject:
user, when known - Schema: wallet.link_failed.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
reason | string | yes | Why, as a snake_case code such as invalid_credentials. The set may grow in a minor release. |
verifierProfile | string | no | The verifier profile the wallet presentation was checked under, such as haip-1.0. |
wallet.presentation_received v1-rc.0
Section titled “wallet.presentation_received v1-rc.0”The OpenID4VP response endpoint accepted a wallet presentation. This is not a sign-in: the flow that asked for it decides.
- Identifier:
urn:qauth:event:wallet.presentation_received:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject: none: the event never carries one
- Schema: wallet.presentation_received.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
verifierProfile | string | yes | The verifier profile the wallet presentation was checked under, such as haip-1.0. |
presentationCount | integer | yes | How many presentations the response held. |
request.csrf_rejected v1-rc.0
Section titled “request.csrf_rejected v1-rc.0”A form post was refused because its CSRF check failed: the token was missing or did not match.
- Identifier:
urn:qauth:event:request.csrf_rejected:v1-rc.0 - Category:
user· Severity:warning· Since: v0.2.0 - Subject:
user, when known - Schema: request.csrf_rejected.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
form | one of sign_in, wallet_sign_in, wallet_link, consent, consent_revocation, or a later value | yes | The form that was posted. The set may grow in a minor release. |
ssf.stream.verification_requested v1-rc.0
Section titled “ssf.stream.verification_requested v1-rc.0”A receiver asked for a verification event on one of its Shared Signals Framework streams (SSF 1.0 §8.1.4). QAuth sends the verification Security Event Token to that stream only.
- Identifier:
urn:qauth:event:ssf.stream.verification_requested:v1-rc.0 - Category:
user· Severity:info· Since: v0.2.0 - Subject:
ssf_stream, when known - Schema: ssf.stream.verification_requested.v1-rc.0.json
| Member | Type | Required | Meaning |
|---|---|---|---|
state | string | no | The opaque value the receiver sent, returned to it in the verification event. Absent when it sent none. |
admin.change_applied v1-rc.0
Section titled “admin.change_applied v1-rc.0”An administrator, a service account or an operator changed something in the realm through an admin operation. Emitted for every such change, in its transaction; no setting turns it off. The admin events of a realm form one hash chain.
- Identifier:
urn:qauth:event:admin.change_applied:v1-rc.0 - Category:
admin· Severity:info· Since: v0.2.0 - Subject: none: the event never carries one
- Schema: admin.change_applied.v1-rc.0.json
- Diff:
data.difflists what changed, with every secret value masked (Admin events)
| Member | Type | Required | Meaning |
|---|---|---|---|
operation | string | yes | The operation’s id in the permission catalog, such as realms.policies.write (ADR-019 Decision 7). |
target | object | yes | What the operation changed. |
target.type | string | yes | What kind of thing the operation changed, as a snake_case code such as realm, client or webhook_subscription. The set grows with the admin API. |
target.id | string | yes | The changed thing’s identifier, such as a realm id or a client_id. It stays valid after the thing is deleted. |
diff | array of object | yes | What the operation changed in the target, field by field. Only changed fields are listed. A nested object is diffed member by member; any other value, an array included, is shown whole. Every secret value is ***. |
approvals | array of object | yes | The approvals the operation ran on, both of a two-admin operation. Empty when it needed none. |
Earlier event names
Section titled “Earlier event names”Before the event contract, QAuth wrote free-form event names to its audit log and its log
lines. Each becomes a registered type. Several earlier names become one type, and the name implied
some data. Since 0.2.0 the auth server records events and writes no audit row; the upgrade
copies every audit row into the event store with this map. A copied event gets the data its name
implies and the members of the old row that have the declared form. A required member an old row
cannot supply gets a fixed value: unknown for a code, false for a flag, an empty list, 0
for a count or the nil UUID for an id. Log lines keep their names.
| Earlier name | Written to | Type | Implied data |
|---|---|---|---|
user.login.success | audit log | urn:qauth:event:user.signed_in:v1-rc.0 | method: password |
user.login.failure | audit log | urn:qauth:event:user.sign_in_failed:v1-rc.0 | method: password |
ui.login.success | audit log | urn:qauth:event:user.signed_in:v1-rc.0 | method: password |
ui.login.failure | audit log | urn:qauth:event:user.sign_in_failed:v1-rc.0 | method: password |
ui.login.csrf_failure | audit log | urn:qauth:event:request.csrf_rejected:v1-rc.0 | form: sign_in |
ui.wallet_login.success | audit log | urn:qauth:event:user.signed_in:v1-rc.0 | method: wallet |
ui.wallet_login.failure | audit log | urn:qauth:event:user.sign_in_failed:v1-rc.0 | method: wallet |
ui.wallet_login.csrf_failure | audit log | urn:qauth:event:request.csrf_rejected:v1-rc.0 | form: wallet_sign_in |
user.logout.success | audit log | urn:qauth:event:user.signed_out:v1-rc.0 | — |
user.logout.failure | audit log | urn:qauth:event:user.sign_out_failed:v1-rc.0 | — |
user.register.success | log line | urn:qauth:event:user.registered:v1-rc.0 | method: password |
user.register.failure | log line | urn:qauth:event:user.registration_failed:v1-rc.0 | — |
oauth.authorize.success | audit log | urn:qauth:event:authorization.completed:v1-rc.0 | — |
oauth.authorize.failure | audit log | urn:qauth:event:authorization.failed:v1-rc.0 | — |
oauth.stepup.required | audit log | urn:qauth:event:step_up.required:v1-rc.0 | — |
oauth.stepup.elevation | audit log | urn:qauth:event:step_up.elevated:v1-rc.0 | — |
oauth.consent.granted | audit log | urn:qauth:event:consent.granted:v1-rc.0 | — |
oauth.consent.denied | audit log | urn:qauth:event:consent.denied:v1-rc.0 | — |
oauth.consent.revoked | audit log | urn:qauth:event:consent.revoked:v1-rc.0 | — |
oauth.consent.csrf_failure | audit log | urn:qauth:event:request.csrf_rejected:v1-rc.0 | form: consent |
consents.revoke.csrf_failure | audit log | urn:qauth:event:request.csrf_rejected:v1-rc.0 | form: consent_revocation |
oauth.token.exchange.success | audit log | urn:qauth:event:token.issued:v1-rc.0 | — |
oauth.token.exchange.failure | audit log | urn:qauth:event:token.request_failed:v1-rc.0 | — |
oauth.revoke.success | audit log | urn:qauth:event:token.revoked:v1-rc.0 | — |
oauth.revoke.failure | audit log | urn:qauth:event:token.revocation_failed:v1-rc.0 | — |
oauth.introspect.success | audit log | urn:qauth:event:token.introspected:v1-rc.0 | — |
oauth.introspect.failure | audit log | urn:qauth:event:token.introspection_failed:v1-rc.0 | — |
oauth.userinfo.success | audit log | urn:qauth:event:userinfo.served:v1-rc.0 | — |
oauth.userinfo.failure | audit log | urn:qauth:event:userinfo.request_failed:v1-rc.0 | — |
oauth.client.registered | audit log | urn:qauth:event:client.created:v1-rc.0 | registration: dynamic |
oauth.client.created | audit log | urn:qauth:event:client.created:v1-rc.0 | registration: developer_api |
oauth.client.updated | audit log | urn:qauth:event:client.updated:v1-rc.0 | — |
oauth.client.deleted | audit log | urn:qauth:event:client.deleted:v1-rc.0 | — |
oauth.client.secret_regenerated | audit log | urn:qauth:event:client.secret_rotated:v1-rc.0 | — |
oauth.client.suspended | audit log | urn:qauth:event:client.suspended:v1-rc.0 | — |
oauth.client.suspension_lifted | audit log | urn:qauth:event:client.suspension_lifted:v1-rc.0 | — |
api_key.created | audit log | urn:qauth:event:api_key.created:v1-rc.0 | — |
api_key.revoked | audit log | urn:qauth:event:api_key.revoked:v1-rc.0 | — |
auth.wallet_link.success | audit log | urn:qauth:event:wallet.linked:v1-rc.0 | — |
auth.wallet_link.failure | audit log | urn:qauth:event:wallet.link_failed:v1-rc.0 | — |
auth.wallet_link.csrf_failure | audit log | urn:qauth:event:request.csrf_rejected:v1-rc.0 | form: wallet_link |
oid4vp.response.received | audit log | urn:qauth:event:wallet.presentation_received:v1-rc.0 | — |