Audit Logs
LumoAuth records an audit trail of authentication events, administrative actions, and data changes within each organization. Audit logs support security monitoring, compliance reporting, and incident investigation, and can be streamed to your SIEM (security information and event management system) through log sinks.
Viewing Audit Logs
Portal
Navigate to Audit logs in the sidebar (under Security, /orgs/{orgId}/portal/audit-logs):
- Filters - Filter by Actor, keyword Search, Event type, Status (success or failure), Severity and a From / To date range, then click Apply filters (Clear resets them)
- Event detail - Each row shows the time, event, actor (with how it authenticated and the truncated IP address), target and details; click Data on a row to open Log entry metadata with the full event context including request metadata
- Export logs - Download logs as CSV. The export contains the whole filtered result, not just the page on screen, up to 100,000 rows. Exporting needs
audit.exportand is itself audited asaudit.exported. On plans without theaudit_exportfeature the button reads Upgrade to export.


Event Categories
The tables below list every event type LumoAuth writes today, grouped by area. Use the
names exactly as shown when you filter by eventType. A name written as a / b is two
events that mirror each other. Most events can end in success or failure; the Result
field (status in the API) tells you which.
Two families of rows are written automatically, whatever screen, API or command made the change:
- Record changes. Creating, changing or deleting users, the organization, roles,
permissions, applications, social login providers, linked identities, agents and webhooks
writes
<type>.created,<type>.updatedor<type>.deleted, with the before/after values inchanges. - Grants and memberships. Adding or removing a role, a permission or a group member
writes
role.assigned/role.removed,permission.granted/permission.revokedorgroup.member_added/group.member_removed.
The screen or API that made the change often writes its own, more specific row as well (for
example client.created next to application.created).
For risk levels and alerting, see Security-relevant events.
Authentication & sessions
| Event | When it's recorded |
|---|---|
user.login | A browser session was created after a successful sign-in (ip_address, user_agent) |
auth.login | A sign-in through the hosted OAuth login form or the JSON login endpoint succeeded or failed (channel: hosted_form or json; reason on failure, e.g. csrf_invalid, captcha_*, locked_out, adaptive_auth_block) |
login.failed | A password, passkey, magic-link or push sign-in failed (method, reason) |
auth.failed | A machine credential failed: API key, Bearer token, SCIM (automatic user provisioning) token, or a passkey that matched no user (auth_method) |
access.denied | A 403 was returned to an authenticated caller |
account.locked | An account was locked after repeated failed sign-ins |
magic_link_login | A user signed in with a magic link |
captcha.login_rejected | CAPTCHA verification failed before the password was checked |
captcha.bypassed | The CAPTCHA provider was unreachable and lenient mode let the request through |
password.breached_at_login | The password used to sign in appears in a known breach; a password change is enforced (breach_count) |
password.breach_check_unavailable | The breached-password service was unreachable, so a password was accepted without that check |
adaptive_auth.decision | Adaptive authentication scored a sign-in (decision, risk_score); a block decision is high risk and raises an alert |
security.ip_blocked | A sign-in was refused by a network block ("Block Tor exit nodes" or "Block datacenter / VPN") before scoring (reason: network_block_tor_exit_node or network_block_vpn_or_datacenter, ip, provider, country) |
adaptive_auth.error | The risk assessment failed during sign-in |
adaptive_auth.ai_assessment | An AI risk assessment ran (risk_score, signals_triggered) or failed |
adaptive_auth.ai_quota_exceeded | The AI risk assessment was skipped because the AI quota is used up |
adaptive_auth.ai_risk_assessment_disabled_by_tenant | The AI risk assessment was skipped because the organization turned it off |
oauth.root_fallback_login | A platform (root) administrator signed in through this organization's login page; severity critical |
password_reset.requested | A password reset was requested by the user or by an administrator (requested_by) |
password_reset_completed | A password-reset link was used |
user.password_changed | A password was changed (source: self_service, password_reset_token, force_password_change or admin_api) |
user.password.set_by_admin | An administrator set a user's password in the portal user editor |
email_verification_token_generated / email_verified | An e-mail verification link was issued / used |
account.pre_verification_bindings_dropped | Verifying the e-mail (from another browser) or resetting the password removed social links and MFA (multi-factor authentication) factors attached before the address was proven, and revoked the user's tokens (trigger: email_verification or password_reset, social_provider, mfa_methods) |
user.pending_signup_removed | Unverified self-service sign-ups were deleted (reason: unverified_signup_expired after 48 hours, or claimed_by_invitation / claimed_by_org_invitation when an invitation claimed the address; users, organizations) |
session.revoked | One session was ended: the user signed out, or revoked a device, or an administrator revoked it |
session.revoked_all | All of a user's sessions, or all of the organization's sessions, were revoked (count) |
tenant.resolution / oauth.tenant_resolution | A public or OAuth endpoint was called for an organization that doesn't exist or is inactive |
Social, enterprise SSO and LDAP sign-in
| Event | When it's recorded |
|---|---|
oauth.social_login_initiated | A social sign-in was started (provider) |
oauth.social_login_success | A social sign-in completed |
oauth.social_login_link_refused | A social sign-in matched an existing local account and was not linked automatically |
user.social_unlinked | A user unlinked a social account (provider) |
oidc_login_initiated / oidc_login_success | A sign-in through an enterprise OIDC identity provider started / completed |
oidc_callback_error / oidc_callback_invalid_state | The OIDC provider returned an error / a callback carried an invalid state |
saml_login_success | A SAML sign-in (LumoAuth as service provider) completed |
saml_login_error / saml_acs_error | Starting a SAML sign-in / processing the SAML response failed |
saml_login_blocked | Adaptive authentication blocked a SAML sign-in |
saml_acs_missing_session, saml_acs_invalid_idp, saml_acs_missing_request_id | A SAML response was rejected because it could not be tied to a sign-in this browser started |
saml_user_provisioned | A user was created just in time from a SAML sign-in |
saml_jit_domain_mismatch | Just-in-time provisioning was refused because the e-mail domain doesn't match the IdP |
saml_legacy_binding_upgraded | A user bound by bare NameID (before per-IdP binding) was re-bound to the organization's only SAML IdP at sign-in (idp_config_id, user_id) |
saml_legacy_binding_ambiguous | A legacy bare-NameID user signed in to an organization with several SAML IdPs; sign-in was refused until an administrator relinks the account (idp_config_id, user_id) |
saml_default_role_skipped | A privileged default role was not assigned during SAML provisioning |
saml_slo_initiated | A SAML single logout to the IdP was started |
saml_slo_error, saml_slo_process_error, saml_slo_request_id_capture_error | A SAML single logout failed |
saml_response_issued / saml_response_error | LumoAuth, as SAML IdP, issued / failed to issue a response to an application (sp_entity_id) |
saml_unknown_sp, saml_invalid_acs, saml_invalid_authnreq_signature | LumoAuth, as SAML IdP, rejected a request (unknown application, wrong ACS URL, bad signature) |
saml_sso_error | LumoAuth, as SAML IdP, failed to process a sign-in request |
saml_unsigned_authnreq_accepted | An unsigned request was accepted because the application allows it; severity warning |
saml_slo_completed / saml_slo_nameid_mismatch | A logout request from an application was processed / refused because the NameID doesn't match the session |
ldap.bind.success / ldap.bind.failed | An LDAP bind with the user's credentials succeeded / failed (user_dn, error_category) |
ldap.user.imported / ldap.user_provisioned | A user was created from the directory on first LDAP sign-in |
ldap.local_account_missing | An LDAP user has no local account and just-in-time provisioning is off |
ldap.account_link_refused | An LDAP sign-in matched an existing account by e-mail that may not be adopted (it has a local password, social links, admin rights, or is bound to another directory entry); sign-in was refused (ldap_config_id, reason) |
ldap.authentication_error | LDAP sign-in failed with an error |
ldap.attr_mapping.error | Required attributes were missing from the directory entry (missing_attrs) |
user.attrs_synced_from_ldap | Profile attributes were updated from the directory at sign-in |
user.email_changed_by_ldap_sync | A user's e-mail was changed by directory sync; severity warning |
MFA Events
Every MFA action is audited under an mfa.* event name and delivered to webhooks with the same name. Entries carry the user as the target, the actor (user, admin, API key or system), the client IP and user agent, and event-specific metadata such as authenticator_id (for example push:5), factor_type, purpose and reason.
| Event | Description |
|---|---|
mfa.enroll.started | A user started enrolling a factor (factor_type) |
mfa.enroll.completed | A factor became active (authenticator_id, factor_type, source: self_service or api) |
mfa.enroll.failed | An enrollment verification code was rejected |
mfa.enroll.deferred | A user chose "Remind me later" (deferral_count, grace_days_left) |
mfa.challenge.issued | A challenge was issued (challenge_id, authenticator_id, factor_type, purpose: login or step_up) |
mfa.challenge.succeeded | A challenge was passed (includes the amr values) |
mfa.challenge.failed | A wrong code or credential, or a push denied on the phone (attempts, reason) |
mfa.push.denied | A push request was denied in the LumoAuth app (push_suspended is true when this denial paused push) |
mfa.push.reported_fraud | The user chose Deny – this wasn't me (initiating_ip, location, user_agent); severity warning |
mfa.factor.removed | A factor was removed (source: user or admin) |
mfa.factor.default_changed | A user changed their default factor (previous) |
mfa.recovery_codes.generated | Recovery codes were generated or regenerated (regenerated, source) |
mfa.recovery_code.used | A recovery code was used (remaining) |
mfa.recovery.started | Account recovery started (method: recovery_code, temporary_access_code or not_me_link) |
mfa.recovery.completed | A recovered user finished re-enrolling (new factor and recovery codes confirmed) |
mfa.tap.issued | An admin issued a temporary access code (reason, ttl_minutes, single_use) |
mfa.locked | MFA was locked after 10 failures in 15 minutes (lock_seconds) |
mfa.policy.changed | The MFA policy changed (changes with from/to values, source: portal or admin_api) |
mfa.trusted_device.added | A user trusted a device (trusted_device_id, days) |
mfa.trusted_device.revoked | Trusted devices were revoked (count, reason: user, password_changed, factor_removed, recovery, high_risk, reported_not_me) |
mfa.enabled | A user enrolled their first factor (also delivered to webhooks as user.mfa_enabled) |
mfa.disabled | Removing an authenticator left the user with no active factor (also delivered as user.mfa_disabled) |
mfa.sms_failed | A wrong code during text-message enrollment |
Related passkey and LumoAuth app events:
| Event | When it's recorded |
|---|---|
passkey.registered | A user registered a passkey (aaguid, authenticator_name) |
passkey.registration_rejected | A passkey was refused because the authenticator is not FIDO certified and the organization requires it |
push_auth.enroll / push_auth.unenroll | A device was enrolled in / removed from LumoAuth app push (device_id, platform) |
push_auth.initiate | A push authentication request was sent to a device |
push_auth.respond | A device approved or denied a push request, or its response was rejected (action) |
Users & profile
| Event | When it's recorded |
|---|---|
user.created / user.updated / user.deleted | A user account was created, changed or deleted, from any surface (portal, Admin API, SCIM, sign-up, just-in-time provisioning, CLI) |
user.blocked | An administrator blocked a user in the portal |
user.roles.updated | An administrator changed a user's roles in the portal user editor |
user.trait.deleted | An administrator deleted a custom attribute (trait) from a user (trait_key) |
user.email_change_requested / user.email_changed | A user asked to change their e-mail / confirmed it from the new address (old_email, new_email) |
user.invitation.sent / user.invitation.resent / user.invitation.revoked | An administrator sent, resent or revoked an invitation |
user.invitation.accepted | An invitee accepted an invitation |
user_invitation.resend_failed | Resending an invitation failed |
user_identity.created / user_identity.updated / user_identity.deleted | A linked social or SSO identity was added, changed or removed |
identity.link.created / identity.link.removed | An administrator linked or unlinked a user's SAML, LDAP or social identity (type, the new or removed binding, previous_binding); the user was signed out and notified |
identity.link.bulk_relinked | An administrator relinked legacy bare-NameID SAML users to an IdP (idp_config_id, relinked_user_ids, skipped) |
organization.created / organization.updated / organization.deleted | A customer organization was created, changed or deleted |
organization.invitation.accepted | A user accepted an invitation to a customer organization |
Roles, permissions, groups & policies
| Event | When it's recorded |
|---|---|
role.created / role.updated / role.deleted | A role was created, changed or deleted |
role.delete_failed | Deleting a role failed |
permission.created / permission.updated / permission.deleted | A permission was defined, changed or deleted |
role.assigned / role.removed | A role was added to or removed from a user or a group (relation: user.role or group.role) |
permission.granted / permission.revoked | A permission was granted to or removed from a user or a role |
group.created / group.updated / group.deleted | A group was created, changed or deleted |
group.delete_failed | Deleting a group failed |
group.member_added / group.member_removed | A user joined or left a group |
abac.attribute_created / abac.attribute_updated / abac.attribute_deleted | An ABAC (attribute-based access control) attribute definition changed |
abac.policy_created / abac.policy_updated / abac.policy_deleted | An ABAC policy was changed in the portal |
abac.policy.updated / abac.policy.deleted | An ABAC policy was changed through the Admin API (old_hash, policy_hash) |
zanzibar.namespace_created / zanzibar.namespace_updated / zanzibar.namespace_deleted | A relationship namespace changed |
zanzibar.tuple_created / zanzibar.tuple_deleted | A relationship tuple was written or deleted in the portal |
zanzibar.sync_completed | Roles and permissions were synced into relationship tuples |
permission_check | The policy decision point answered a permission check for a user or an agent (permission, granted) |
abac_check | The ABAC engine evaluated an access request |
zanzibar_check | A relationship check ran (the portal tester or the decision point) |
policy.parsed / policy.parse_failed / policy.parse_error | AI policy authoring turned a plain-language policy into a draft / could not |
policy.created / policy.create_rejected / policy.create_error | An AI-authored policy was saved / refused / failed |
Applications & tokens
| Event | When it's recorded |
|---|---|
client.created / client.updated / client.deleted | An OAuth application was created, edited or deleted in the portal |
client.configuration_updated | An application's advanced configuration was saved (form_type) |
client.secret_rotated | An application's client secret was rotated |
client.credentials_synced / client.credentials_sync_failed | Client credentials were pushed / failed to push to a secrets manager |
application.created / application.updated / application.deleted | Record change on an OAuth application, from any surface |
saml_client.created | A SAML application was created from Applications |
saml_client_created / saml_client_updated / saml_client_deleted | A SAML application was changed on the SAML page |
oauth.client_registered | A client registered through dynamic client registration |
oauth.register / oauth.client_configuration | A dynamic registration request / a registration-management request was refused |
oauth.initial_access_token_hash_upgrade | A legacy plaintext initial access token was re-stored as a hash |
oauth.cimd_client_resolved / oauth.cimd_fetch_failed | A client ID metadata document was fetched and accepted / rejected (reason names the rule that failed) |
oauth.cimd_document_checked | An admin ran a client ID metadata document through the portal check tool |
oauth.client_resolution | A request named an unknown, inactive or other-organization client_id |
oauth.authorize | An authorization request was rejected (invalid request object or request_uri, unknown organization) |
oauth.authorize.none_with_scope | response_type=none was used with scopes, which were ignored |
oauth.par / oauth.par_created | A pushed authorization request was rejected / accepted |
oauth.authorization_issued | An authorization response was returned to the application (response_type, response_mode) |
oauth.authorization_code_issued | An authorization code was created (pkce_used) |
oauth.authorization_denied | The user declined the consent screen |
consent.revoked | A user revoked an application's access from their account |
oauth.token | The token endpoint refused client authentication |
oauth.token.state_binding_absent / oauth.token.state_binding_mismatch | The token request didn't forward the authorization state / forwarded a different one |
oauth.access_token_issued | Tokens were issued for the authorization-code, CIBA or device-code grant (grant_type, dpop_bound, scopes) |
oauth.client_token_issued | A client-credentials token was issued |
oauth.token_exchange | A token exchange succeeded or was refused |
oauth.token_introspection | A token was introspected (token_active) |
oauth.token_revoked | An application revoked a token at the revocation endpoint |
token.revoked | An administrator revoked OAuth tokens (one token, a user's, or a client's) |
oauth.security.code_reuse_detected / oauth.security.refresh_token_reuse_detected | An authorization code or refresh token was replayed |
oauth.security.tokens_revoked | Tokens were revoked in response to a replay (reason) |
oauth.ciba / oauth.ciba_request_created | A CIBA request was refused / accepted |
oauth.token.ciba | A CIBA token request was refused (invalid auth_req_id, user denied, …) |
oauth.device_authorization | A device authorization request was accepted or refused |
oauth.device_verify | A user entered a device code or approved a device |
oauth.token.device_code | A device-code token request was refused (expired, polling too fast, …) |
txn.token_issued / txn.token_rejected | A transaction token was issued / refused |
backchannel_logout_sent / backchannel_logout_failed | A back-channel logout notice was delivered / failed (client_id) |
xaa.grant_policy_created / xaa.grant_policy_deleted | A cross-app access grant policy was created / deleted |
xaa.trusted_issuer_created / xaa.trusted_issuer_deleted | A trusted identity-assertion issuer was added / removed |
xaa.id_jag_issued / xaa.id_jag_redeemed / xaa.id_jag_rejected | An identity assertion grant was issued, redeemed or refused |
API keys & machine credentials
| Event | When it's recorded |
|---|---|
api_key.created / api_key.create_failed | An organization API key was created / creation failed (scopes) |
api_key.rotated / api_key.rotate_failed | A key was rotated (old_key_prefix, new_key_prefix) / rotation failed |
api_key.scopes_updated | A key's scopes changed (old_scopes, new_scopes) |
api_key.revoked / api_key.deleted | A key was revoked / deleted |
api_key.used | A request authenticated with an API key (masked_prefix, path) |
scim.token_generated / scim.token_regenerated | A SCIM bearer token was created / replaced |
Agents & JIT
| Event | When it's recorded |
|---|---|
agent.created / agent.updated / agent.deleted | Record change on an agent, from any surface |
agent.activated, agent.suspended, agent.revoked, agent.status_changed | An agent's status changed (from, to) |
agent.scopes_changed | An agent's capabilities changed (added, removed) |
agent.token_issued, agent.key_rotated, agent.key_revoked, agent.credentials_rotated | Agent credentials were minted or rotated through the Admin API |
agent.credentials_revoked | An agent's live credentials were revoked because it was suspended or revoked |
agent.deactivated_dormant | The lifecycle job deactivated an agent with no recent activity |
agent.reauth_failed, agent.reauth_rate_limited, agent.reauth_refused_mfa | Password re-authentication for agent registration failed, was throttled, or was refused for an MFA account |
agent.test_run | A test token or capability check was run from the portal |
agent.capability_check_denied | An agent's capability check was denied |
agent.access_policy_created / agent.access_policy_deleted | An agent access policy was created / deleted |
agent.access_policy_enabled / agent.access_policy_disabled | An agent access policy was switched on / off |
agent.access_policy_denied | An agent access policy denied a request (reason, policy) |
agent.approval.requested / agent.approval.email_fallback | A human approval was requested, by push / by e-mail because push wasn't available |
agent.attestation.accepted / agent.attestation.rejected | A workload attestation was accepted (provider, subject) / rejected |
a2a.card_config_changed / a2a.card_verify_failed | An agent's A2A card settings changed / a card failed verification |
agent_registry.synced / agent_registry.sync_failed | Agents were synced from an external agent registry |
agent_ecosystem.<kind>.<action> | An agent registry, AI gateway or tracing integration changed: <kind> is registry, gateway or trace; <action> is created, updated, tested, enabled, disabled or deleted (e.g. agent_ecosystem.gateway.tested) |
ai_gateway.key_provisioned / ai_gateway.key_provision_failed | An AI gateway key was issued for an agent / issuing failed |
ai_gateway.key_revoked / ai_gateway.key_revoke_failed | An agent's AI gateway key was revoked / revoking failed |
oauth.agent_token_issued / oauth.token_exchange_agent | An agent obtained a token with its credentials / with a workload identity |
aauth.agent_token_issued / aauth.auth_token_issued / aauth.platform_token.issued | An AAuth agent, auth or platform token was issued |
aauth.authorization_granted / aauth.authorization_denied | A user approved / declined an AAuth authorization request |
aauth.signature_verification_failed | An AAuth request's HTTP message signature did not verify |
aauth.consent_record_missing | Identity claims were withheld because no consent record exists |
aauth.agent_updated, aauth.agent_activated, aauth.agent_revoked, aauth.agent_deleted | An AAuth agent was changed in the portal |
aauth.resource_created / aauth.resource_updated / aauth.resource_deleted | An AAuth resource was changed |
mcp_server.created / mcp_server.updated / mcp_server.deleted | An MCP server registration changed |
mcp.challenge_issued | An MCP resource returned a 401 authorization challenge |
mcp.metadata_not_found | Protected-resource metadata was requested for an unknown MCP server |
mcp.tool.authorization | An MCP tool call was authorized or denied for an agent (server_id, tool) |
jit.task_created / jit.task_completed | An agent task was created / completed |
jit.permission_requested | An agent requested a just-in-time permission |
jit.permission_auto_approved / jit.permission_policy_approved | A request was approved automatically (low risk) / by an approval policy |
jit.hitl_triggered | A request needs a human approver (risk_level) |
jit.permission_approved / jit.permission_denied | A request was approved or denied by a reviewer on any channel (portal inbox, API, mobile, approval channel), or denied by policy. Portal decisions were logged as jit.request.approved / jit.request.denied before 2026-09-28; those names remain webhook event types only |
jit.token_issued / jit.permission_revoked | A JIT token was issued / revoked |
jit.approval_policy_created / jit.approval_policy_revoked | A JIT approval policy was created / revoked |
jit.callback_failed / jit.callback_blocked | A decision callback failed / was blocked because it targets a private network |
ciba.agent_initiated | An agent started (or was refused) a CIBA request on behalf of a user |
ciba.agent_approved / ciba.agent_denied | The user approved / denied an agent-initiated CIBA request |
caep.task_suspended | A task was suspended by a continuous access evaluation signal |
approval_channel.created / approval_channel.updated / approval_channel.deleted | A human-approval channel changed |
approval_channel.enabled / approval_channel.disabled / approval_channel.tested / approval_channel.token_rotated | An approval channel was switched on or off, tested, or had its token rotated |
approval_channel.decision / approval_channel.decision_rejected | A decision arrived through an approval channel / was refused (reviewer not permitted, unknown request) |
vault.connection_created / vault.connection_updated / vault.connection_deleted | A token vault connection changed |
vault.grant_linked / vault.grant_revoked / vault.refresh_failed | A user linked or revoked an account in the token vault / a refresh was rejected by the provider |
vault.token_issued | An agent retrieved a token from the vault |
Organization settings & integrations
| Event | When it's recorded |
|---|---|
tenant.created / tenant.updated / tenant.deleted | Record change on the organization itself (name, slug, status and settings) |
signing_key.generated, signing_key.rotated, signing_key.primary_set, signing_key.imported, signing_key.revoked, signing_key.deleted | Signing key lifecycle (kid, algorithm) |
webhook.created / webhook.updated / webhook.deleted | A webhook endpoint was added, changed or removed |
webhook.secret_rotated | A webhook's signing secret was rotated |
custom_domain.added / custom_domain.add_failed / custom_domain.verified | A custom domain was added / couldn't be added / passed DNS verification |
custom_domain.set_primary / custom_domain.set_primary_failed | A domain was made primary / couldn't be |
custom_domain.activated / custom_domain.disabled / custom_domain.deleted | A domain was switched on, off, or removed |
custom_domain.needs_reverification | DNS re-verification kept failing past the grace period, so the domain was flagged; severity warning |
email_template.updated / email_template.reverted | An e-mail template was customized / reverted to the default |
email_provider.created / email_provider.updated / email_provider.tested / email_provider.deleted | A custom e-mail provider changed |
sms_provider.created / sms_provider.updated / sms_provider.deleted | A text-message provider changed |
sms.sent / sms.failed / sms.rate_limited | A text message was sent / failed / was refused by the rate limit |
social_login_provider.created / social_login_provider.updated / social_login_provider.deleted | A social login provider was configured |
oidc_idp_config_created / oidc_idp_config_updated / oidc_idp_config_deleted | An enterprise OIDC identity provider changed |
oidc_idp_discover_failed | OIDC discovery for a new identity provider failed |
idp_connector.configured / idp_connector.discovery_failed | An identity provider was set up from the integrations catalog / its discovery failed |
saml_idp_config_created / saml_idp_config_updated / saml_idp_config_deleted | A SAML identity provider changed |
saml.metadata_imported | SAML IdP metadata was fetched from a URL or file |
ldap.configured / ldap.updated / ldap.toggled / ldap.deleted | An LDAP directory connection changed |
scim.configuration_updated | Inbound SCIM settings changed |
scim.<resource>.<operation> | A SCIM client changed data: scim.user.create, .replace, .patch, .delete, the same for scim.group.*, scim.me.replace / scim.me.patch, scim.subscription.create / .delete, scim.mixed.bulk (reads are not recorded) |
scim_outbound.configuration_updated / scim_outbound.connection_test_failed | Outbound SCIM provisioning settings changed / its connection test failed |
log_sink.created / log_sink.updated / log_sink.enabled / log_sink.disabled / log_sink.deleted | A log shipper changed |
alert_channel.created / alert_channel.updated / alert_channel.enabled / alert_channel.disabled / alert_channel.tested / alert_channel.deleted | A security alert channel changed or was tested |
analytics.integration_updated / analytics.integration_enabled / analytics.integration_disabled / analytics.integration_deleted | A product-analytics integration changed |
crm.integration_updated / crm.integration_enabled / crm.integration_disabled / crm.integration_deleted | A CRM integration changed |
crm.record_synced | A record was pushed to the CRM |
hris.integration_created / hris.integration_updated / hris.integration_toggled / hris.integration_deleted | An HR system connection changed |
hris.connection_test | An HR connection was tested (success or failure) |
hris.sync_requested / hris.sync_completed / hris.sync_failed | An HR sync was started / finished / failed (run_id, dry_run) |
risk_provider.created / risk_provider.updated / risk_provider.toggled / risk_provider.deleted | A risk-signal provider changed |
device_posture.integration_updated / device_posture.integration_deleted | A device-posture integration changed |
captcha.created / captcha.updated / captcha.deleted | A CAPTCHA integration changed |
secrets_manager.created / secrets_manager.updated / secrets_manager.deleted | A secrets-manager connection changed |
deploy_secret_target.created / deploy_secret_target.updated / deploy_secret_target.deleted | A secret deployment target changed |
fido_mds.refreshed / fido_mds.refresh_failed | The FIDO metadata service was refreshed / the refresh failed |
ssf.stream_created / ssf.stream_deleted / ssf.verification_requested | A Shared Signals transmitter stream was created, deleted, or sent a verification event |
ssf.set_delivered / ssf.set_delivery_failed | A security event was delivered / failed to deliver to a receiver |
ssf.receiver_created / ssf.receiver_deleted / ssf.receiver_status_changed / ssf.receiver_bearer_rotated | A Shared Signals receiver stream changed |
ssf.receiver.<event> | A received security event was processed or rejected, e.g. ssf.receiver.session_revoked, ssf.receiver.credential_change |
ssf.receiver.set_rejected | An incoming security event token was rejected before processing |
ai_theme.login_page_failed / ai_theme.consent_page_failed | AI theme generation for the login / consent page failed |
billing.checkout_started / billing.portal_opened / billing.stripe_binding_reset | A plan checkout or the billing portal was opened / the Stripe binding was reset |
billing.addon_added / billing.addon_removed / billing.addon_trial_started | An add-on was bought, removed or trialed |
billing.checkout_session_completed, billing.customer_subscription_created, billing.customer_subscription_updated, billing.customer_subscription_deleted, billing.invoice_payment_failed | A Stripe billing event was applied to the organization (before, after) |
billing.quota_enforced | The quota job enforced a plan limit; severity warning |
Compliance & GDPR
| Event | When it's recorded |
|---|---|
data.exported | An organization data export, or a user's personal data export (format) |
audit.exported | The audit log was exported (portal CSV or API) |
gdpr.dsr.created / gdpr.dsr.updated | A data subject request was opened / changed status |
gdpr.dsr.identity_challenge_issued / gdpr.dsr.identity_verified | The requester's identity was challenged / verified (method) |
gdpr.erasure.completed / gdpr.erasure.failed | A user was erased / erasure failed |
gdpr.erasure.cross_tenant_scrub | An erased user's data was scrubbed across organizations (rows_scrubbed) |
gdpr.portability.transmitted | Personal data was sent to another controller |
gdpr.restriction.applied / gdpr.restriction.lift_scheduled / gdpr.restriction.lifted | Processing restriction for a user was applied, scheduled to lift, or lifted |
gdpr.consent.granted / gdpr.consent.withdrawn / gdpr.consent.expired | A processing consent was given, withdrawn or expired (purpose) |
gdpr.reconsent.triggered | Users were asked to consent again (affected_users) |
gdpr.cookie_consent.recorded | A cookie consent choice was stored |
gdpr.parental_consent.initiated / gdpr.parental_consent.verified | Parental consent for a child was requested / verified |
gdpr.automated_decision.recorded / gdpr.automated_decision.contested / gdpr.automated_decision.reviewed | An automated decision was logged, contested, or reviewed by a person |
gdpr.breach.created / gdpr.breach.authority_notified / gdpr.breach.subjects_notified | A breach incident was opened / the authority or data subjects were notified |
gdpr.dpia.created / gdpr.dpia.submitted / gdpr.dpia.approved / gdpr.dpia.rejected | A DPIA moved through review |
gdpr.policy.created / gdpr.policy.published / gdpr.policy.publish_blocked | A privacy policy version was drafted / published / blocked from publishing (missing) |
gdpr.ropa.updated / gdpr.ropa.deactivated | A processing activity was edited / deactivated |
gdpr.settings.updated | Privacy settings changed |
gdpr.subprocessor.announced / gdpr.subprocessor.deprecated | A sub-processor was announced / retired |
gdpr.recipient_notification.dispatched / gdpr.recipient_notification.delivered / gdpr.recipient_notification.dead_letter | Recipients were told about a data subject action / delivery succeeded / gave up |
gdpr.lifecycle.dormant_processed | The retention job processed dormant accounts |
security.audit_log_retention_deletion | Audit rows older than the retention period were deleted (deleted_count, retention_days) |
security.consent_integrity_violation | A user's consent record chain failed its integrity check; severity critical |
Operator actions
Changes LumoAuth operators make to your organization or its users at your request (plan or
add-on changes by contract, suspending or reactivating the organization, enabling the
allow_root_admin_login fallback) are written to your organization's log as admin.tenant.*,
admin.user.* and billing.admin_* events, and admin.tenant.* / admin.user.* always raise
a high-risk alert.
Security-relevant events
These events are written the same way from the portal, the Admin API, SCIM and the CLI,
because they are emitted by the service that owns the change rather than by one screen.
The Risk column is what drives alerts; events not mapped to a risk count as critical when their severity is critical, medium when they fail or carry severity warning or error, and low otherwise.
| Event | When | Risk |
|---|---|---|
login.failed | A password, passkey, magic-link or push sign-in failed. Recorded against the organization whose login page was used, so it is visible in that organization's log (metadata.method: password, passkey, magic_link or push; reason) | medium |
auth.failed | A machine credential failed: invalid, expired or cross-organization API key, invalid Bearer token, bad SCIM token, a passkey that matched no user (metadata.auth_method) | medium |
access.denied | Any 403 answered to an authenticated caller (route, auth method) | medium |
account.locked | An account was locked after repeated failed sign-ins | high |
oauth.security.code_reuse_detected | An authorization code was replayed | high |
oauth.root_fallback_login | A LumoAuth operator signed in through this organization's login page (allow_root_admin_login) | critical |
role.assigned / role.removed | A role was added to or removed from a user or group, from any surface | high / low |
user.roles.updated | Roles changed in the portal user editor | high |
permission.granted / permission.revoked | A permission was granted to or removed from a user or role | high / low |
group.member_added / group.member_removed | A user joined or left a group | low |
signing_key.generated, signing_key.rotated, signing_key.primary_set | Signing key lifecycle | high |
signing_key.imported, signing_key.revoked, signing_key.deleted | Signing key import and removal | critical |
agent.created, agent.updated, agent.deleted | Agent registry changes | low |
agent.scopes_changed | An agent's capabilities changed | high |
agent.status_changed, agent.activated, agent.suspended, agent.revoked | Agent lifecycle and kill switch | low |
agent.token_issued, agent.key_rotated, agent.key_revoked, agent.credentials_rotated | Agent credentials minted or rotated through the Admin API | low |
webhook.created / webhook.updated / webhook.deleted | A webhook endpoint was added, changed or removed | low |
session.revoked / session.revoked_all | One session, or all of a user's or the organization's sessions, revoked | low |
token.revoked | OAuth tokens revoked by an administrator (one token, a user's, or a client's) | low |
data.exported | An organization data export, or a user's personal data export | high |
audit.exported | The audit log was exported (portal CSV or API) | high |
password_reset.requested | A password reset was requested, by the user or by an administrator (metadata.requested_by). Renamed from password_reset_requested: update saved filters and SIEM rules | low |
user.email_change_requested / user.email_changed | A user asked to change their e-mail / confirmed it from the new address | low |
user.password_changed with metadata.source admin_api, admin or portal | An administrator set another user's password through the Admin API or the portal | high |
user.password.set_by_admin | An administrator set a user's password in the portal (the Admin API equivalent is user.password_changed with source: admin_api) | high |
mfa.tap.issued, mfa.factor.removed, mfa.disabled, mfa.policy.changed | Credential-takeover primitives | high |
mfa.locked, mfa.push.reported_fraud, mfa.recovery.completed | MFA lockout, a reported push, a finished account recovery | high |
api_key.created, api_key.scopes_updated, client.secret_rotated, scim.token_generated, scim.token_regenerated | Credentials minted for machines | high |
admin.tenant.*, admin.user.*, super_admin.* | Actions taken on the organization or its users by LumoAuth operators | high |
impersonation.* | A LumoAuth operator impersonated a user | critical |
gdpr.erasure.completed, gdpr.erasure.cross_tenant_scrub | A user was erased | high |
security.audit_log_retention_deletion | Audit rows were deleted by the retention job | high |
security.consent_integrity_violation | A consent record chain failed its integrity check | critical |
organization.deleted | A customer organization was deleted | high |
adaptive_auth.decision with metadata.decision block | Adaptive authentication refused a sign-in (risk level or network block) | high |
security.ip_blocked | A network block (Tor / datacenter-VPN) refused a sign-in; alerted through the matching adaptive_auth.decision block row | medium |
Failure rows for credentials and 403s are rate limited to one per credential, route and
event per minute, so a credential-stuffing burst cannot flood the log.
Who did it: actor attribution
Every row records how the actor authenticated in authMethod (API field; auth_method
in exports and log shippers): session, api_key, bearer, scim, agent or system.
Machine actors are no longer disguised as the person behind them:
| Caller | actorType | actorId / actorName | Also recorded |
|---|---|---|---|
| Browser session or user access token | user | The user | metadata.oauth_client_id for tokens |
| Organization API key | api_key | The key's id and name | metadata.api_key_id, metadata.actor_owner_id (the key's creator) |
AI agent (agent token or agk_ key) | agent | The agent_id and name | metadata.actor_owner_id (the agent's owner) |
| SCIM provisioning | scim | — | metadata.actor_owner_id when the SCIM token maps to a user |
| Console command or background job | system | — | — |
All rows written by one request share one requestId, so you can group them. Stored IP
addresses are truncated (/24 for IPv4, /48 for IPv6), session ids are stored as a keyed
hash, and tokens that appear in URL paths (reset, magic-link, invitation, consent links) are
replaced with [REDACTED].
Alerts for high-risk events
Events with risk high or critical (see the table above; unmapped events count as
critical when their severity is critical) are pushed as security alerts as they are written:
- to the platform's own security sinks, operated by LumoAuth, and
- to the organization's own Alert channels, filtered by each
channel's minimum severity (default
high).
Critical events are also appended to an emergency log file on the server, so they survive a log-pipeline outage. Alerts never block the audited operation.
Erasure and audit rows
Deleting a user from the portal or the Admin API is a full Article 17
erasure (tokens, sessions, login attempts, consents and other side tables are cleared, and
Article 19 recipients are notified), recorded as gdpr.erasure.completed plus user.deleted (admin.user.deleted when a LumoAuth operator performed the deletion).
When a user is erased under GDPR Article 17, their audit rows are pseudonymised: e-mail
addresses, names and before/after values that identify them are replaced, including rows
where they appear only as the owner of an API key or agent (metadata.actor_owner_id). The
erasure itself does not write a new row containing the original values.
Log Entry Structure
Each audit log entry contains:
| Field | Description | Example |
|---|---|---|
| Timestamp | When the event occurred | 2025-02-01T14:30:00Z |
| Event Type | Event identifier | user.login |
| Actor | User, API key, agent, SCIM or system that triggered the event | alice@acme.com |
| Auth method | How the actor authenticated | api_key |
| Target | Resource affected | user:bob-uuid |
| IP Address | Source IP, truncated to its /24 (IPv4) or /48 (IPv6) prefix | 192.168.1.0/24 |
| User Agent | Browser/client info | Mozilla/5.0... |
| Geolocation | Approximate location | New York, US |
| Details | Additional context | {"method": "passkey"} |
| Result | Success or failure | success |
Querying via API
Audit logs are read through the admin API under /orgs/{orgId}/api/v1/admin/audit-logs.
# Get recent audit logs
curl https://your-domain.com/orgs/{orgId}/api/v1/admin/audit-logs \
-H "Authorization: Bearer {admin_token}"
# Filter by event type (camelCase param name)
curl "https://your-domain.com/orgs/{orgId}/api/v1/admin/audit-logs?eventType=login.failed" \
-H "Authorization: Bearer {admin_token}"
# Filter by actor (user ID, not email) and date range
curl "https://your-domain.com/orgs/{orgId}/api/v1/admin/audit-logs?actorId=<userId>&from=2025-01-01&to=2025-02-01" \
-H "Authorization: Bearer {admin_token}"
Supported query parameters: eventType, action, actorId (alias userId), targetType (alias resourceType), targetId, severity, ipAddress, search, from/startDate, to/endDate, plus page and limit for pagination.
The response is paginated:
{
"data": [ /* audit log entries */ ],
"meta": { "total": 904, "page": 1, "limit": 50, "totalPages": 19, "hasNextPage": true, "hasPreviousPage": false },
"resourceType": "audit_logs"
}
Related endpoints under the same base path:
| Endpoint | Purpose |
|---|---|
GET /audit-logs/{logId} | Fetch a single entry |
GET /audit-logs/stats | Aggregate event counts |
GET /audit-logs/actions | List distinct actions/event types |
GET /audit-logs/export?format=csv|json | Export filtered logs (CSV by default, format=json for JSON; at most 10,000 rows — the portal CSV export goes to 100,000) |
GET /audit-logs/retention | Read the retention policy |
PUT /audit-logs/retention | Update the retention policy |
Log Retention
| Setting | Default | Configurable |
|---|---|---|
| Retention Period | 730 days (2 years); minimum 90, maximum 3650, capped by the plan's limit | Yes |
Configure retention in the portal under Privacy overview → Settings → Data retention (/orgs/{orgId}/portal/gdpr/settings): set Audit log retention (days) and click Save GDPR settings. The field starts at 730 days. The retention API above (PUT /audit-logs/retention) sets it programmatically.

Audit rows are pruned by a daily platform job, which applies each
organization's own settings and only runs for organizations that have data retention
enabled. When autoDelete has been set to false through the retention API, audit rows are never pruned (the portal has no switch for this). The retention
period is never shorter than 90 days (or the organization's security retention in years,
when set), and each deletion is recorded as security.audit_log_retention_deletion.
Related Guides
- GDPR Compliance - Data subject requests and privacy
- Adaptive MFA - Security events and risk scoring
- Webhooks - Real-time event notifications