Skip to content

Audit event catalog

The OP emits structured audit events from a closed catalog defined in op/audit.go. Each event is a stable string identifier of shape <area>.<verb> (or <area>.<verb>.<qualifier>) so SOC dashboards can pre-aggregate by area without parsing free-form messages.

Subscribing

go
op.New(
    /* required options */
    op.WithAuditLogger(slog.New(myJSONHandler)),
)

op.WithAuditLogger takes a *slog.Logger. Each event records as a structured log entry where the msg is the event identifier (e.g. "token.issued") and the attributes carry the request-id, subject, client-id, and an extras group with category-specific fields.

If WithAuditLogger is not supplied, audit events fall through to the logger configured by WithLogger (or slog.Default()).

Prometheus mirror

A curated subset of these events is mirrored onto Prometheus counters when WithPrometheus is configured. A single emission updates both the slog stream and the matching counter — there is no separate metrics emit step.

Common attributes

Every event carries:

AttributeTypeNotes
request_idstringper-request identifier (propagated via X-Request-ID if set)
subjectstringOIDC sub of the affected user; empty for pre-authn events
client_idstringOAuth client_id; empty for account-management events
extrasgroupcategory-specific fields (see each section)

Event catalog

Account management

Most fire from out-of-band admin paths the OP does not host directly. The catalog exists so a single subscription point covers SOC dashboards.

EventFires when
account.createduser account provisioned
account.deleteduser account removed
account.email.addedemail address added to account
account.email.verifiedemail ownership proven (link / OTP)
account.email.removedemail address removed
account.email.set_primaryprimary email changed
account.passkey.registeredWebAuthn credential added
account.passkey.removedWebAuthn credential removed
account.totp.enabledTOTP enrollment completed
account.totp.disabledTOTP removed
account.password.changedpassword reset / changed
account.recovery_codes.regeneratedrecovery batch reissued
recovery.support_escalationmanual recovery / support override invoked
federation.linkedexternal IdP credential linked
federation.unlinkedexternal IdP credential unlinked

Login / MFA / step-up

Fire from the authenticator chain after each factor resolves.

EventFires when
login.successprimary credential verified, subject bound
login.failedprimary credential rejected
mfa.requiredsession AAL below requirement; second factor demanded
mfa.successsecond factor accepted
mfa.failedsecond factor rejected
step_up.requiredRP requested higher acr_values; user re-prompted
step_up.successstep-up factor accepted
extras
  • factorpassword, passkey, totp, email_otp, captcha, recovery_code, or a user-defined Step kind
  • aal — assurance level the factor raised the session to
  • amr_values — RFC 8176 §2 codes contributed to the amr claim
EventFires when
consent.granteduser clicked consent in the prompt
consent.granted.first_partyfirst-party auto-consent applied (no prompt)
consent.granted.deltadelta-consent triggered re-prompt for newly requested sensitive scope
consent.skipped.existingexisting grant already covered the request; no prompt
consent.revokeduser revoked a prior grant
extras
  • scopes_granted, scopes_requested — string slices
  • audience — when scope is per-audience

Codes & tokens

Fire from the authorize-code path and the token endpoint.

EventFires when
code.issuedauthorization code minted
code.consumedcode redeemed at /token
code.replay_detectedcode presented twice — chain revoked
token.issuedaccess token + (optional) refresh + (optional) id_token issued
token.refreshedrefresh token rotated; new access token minted
token.revokedtoken revoked via /revoke or grant cascade
refresh.replay_detectedrefresh token presented past rotation grace — chain revoked
extras
  • grant_typeauthorization_code, refresh_token, client_credentials
  • formatjwt or opaque for the access token
  • offline_access — bool; true on offline_access chain
  • cnfdpop_jkt or mtls_x5t#S256 when sender-bound

Sessions & logout

EventFires when
session.creatednew browser session minted (post-login)
session.destroyedsession deleted (logout, expiry, eviction)
logout.rp_initiatedRP-Initiated Logout invoked
logout.back_channel.deliveredBack-Channel logout token delivered to RP
logout.back_channel.failedBack-Channel delivery failed (HTTP error / timeout / verification)
bcl.no_sessions_for_subject/end_session named a subject but no sessions resolved
bcl.no_sessions_for_subject rationale

Under a volatile SessionStore (Redis without persistence, in-memory under maxmemory eviction) this event is the signal that a session was evicted between establishment and logout — narrowing OIDC Back-Channel Logout 1.0 §2.7's best-effort delivery floor to zero. INFO-level by design: under volatile placement the gap is expected; SOC tooling should alert on elevated rates rather than per-event. The event includes the configured WithSessionDurabilityPosture so dashboards can split "expected gap under volatile" from "unexpected gap under durable".

Defensive

Fire from request-validation paths that detect abuse signals or operator-visible policy hits.

EventFires when
rate_limit.exceededrequest rejected by rate limiter
rate_limit.bypassedrate-limit bypass token consumed (operator override)
pkce.violationPKCE verifier mismatch / plain rejected / missing on FAPI
redirect_uri.mismatchredirect URI did not match the registered list
alg.legacy_useda legacy alg path was reached (telemetry; rejected by the verifier)

Dynamic Client Registration

Fire from /register and /register/{client_id}.

EventFires when
dcr.iat.consumedInitial Access Token redeemed
dcr.iat.expiredIAT presented past TTL
dcr.iat.invalidIAT signature / format invalid
dcr.open_registration_usedopen (no-IAT) registration accepted
dcr.client.registerednew client created
dcr.client.metadata_readRAT-bearing GET against /register/{client_id}
dcr.client.metadata_updatedRAT-bearing PUT against /register/{client_id}
dcr.client.deletedRAT-bearing DELETE against /register/{client_id}
dcr.rat.invalidRegistration Access Token rejected
dcr.metadata.validation_failedmetadata payload failed policy

Stability

Audit event names are part of the public API surface:

  • New events MAY be added in any minor release.
  • Existing event names are renamed only in a major release with a deprecation notice.

Pin your dashboards on the names; do not rely on the order or the extras shape for any field not documented here.

Verifying this list

sh
git clone https://github.com/libraz/go-oidc-provider.git
cd go-oidc-provider
grep -hE 'AuditEvent\("[a-z_.]+"\)' op/audit.go \
  | grep -oE '"[a-z_.]+"' | sort -u

The output is the closed catalog this page mirrors.