Monitoring, MFA stats
Observe MFA enrollment, challenges, and step-up activity
Athena's analytics page surfaces MFA-related metrics. This page describes what's collected and why.
Metrics
MFA enrollment rate
SELECT
COUNT(*) FILTER (WHERE 'totp' = ANY(credential_types) OR 'webauthn' = ANY(credential_types)) AS enrolled,
COUNT(*) AS total,
(COUNT(*) FILTER (WHERE 'totp' = ANY(credential_types) OR 'webauthn' = ANY(credential_types)) * 100.0 / NULLIF(COUNT(*), 0)) AS percent
FROM identities;Healthy target: ~80% for high-security deployments, ~30%+ for general consumer apps.
Enrollment over time
Track new enrollments via Athena → Security → Audit Log filtered to event_type IN ('mfa.totp_enrolled', 'mfa.webauthn_enrolled').
Step-up frequency
SELECT DATE(created_at), COUNT(*)
FROM security_audit
WHERE event_type = 'auth.aal2_stepup_completed'
GROUP BY 1 ORDER BY 1 DESC LIMIT 30;Trend should match the rate of sensitive-operation usage. A drop indicates either lower sensitive activity or AAL2 is failing.
TOTP vs WebAuthn split
SELECT
COUNT(*) FILTER (WHERE 'webauthn' = ANY(credential_types)) AS webauthn_users,
COUNT(*) FILTER (WHERE 'totp' = ANY(credential_types)) AS totp_users,
COUNT(*) FILTER (WHERE 'webauthn' = ANY(credential_types) AND 'totp' = ANY(credential_types)) AS both
FROM identities;WebAuthn is phishing-resistant; TOTP isn't. Higher WebAuthn % is better.
MFA challenge failures
SELECT identity_id, COUNT(*)
FROM security_audit
WHERE event_type = 'mfa.challenge_failed'
AND created_at > NOW() - INTERVAL '7 days'
GROUP BY 1 HAVING COUNT(*) >= 3;Identities with repeated MFA failures: could indicate lost authenticator, or an attacker who has the password but not the second factor.
Alerts
- Enrollment rate dropping: incentive structure changed; investigate UX.
- MFA challenge failure rate spiking: distributed attack or authenticator outage.
- AAL2 step-up consistently 0: configuration broke, sensitive operations not actually requiring AAL2.
Per-domain breakdown
CIAM and IAM have different MFA expectations:
- IAM should be > 95% enrollment (it's employees).
- CIAM enrollment is voluntary and lower; > 30% is good.
Show breakdown in Athena's analytics:
SELECT
CASE WHEN i.schema_id = 'admin' THEN 'iam' ELSE 'ciam' END AS domain,
COUNT(*) FILTER (WHERE 'totp' = ANY(credential_types) OR 'webauthn' = ANY(credential_types)) AS enrolled,
COUNT(*) AS total
FROM identities i
GROUP BY 1;(This is a CIAM-vs-IAM split assuming you can detect domain from schema_id; in reality the Kratos databases are separate, so query each.)