ASVS 5.0 V6.5.6 requires that any authentication factor, including physical devices like hardware keys and phones, can be revoked if it is stolen or lost. It is a Level 3 requirement.
Why it matters
A lost security key is a working credential in someone else's hands until you disable it. If the only way out is a support ticket that takes two days, the exposure window is two days.
How to implement it
Model each factor as a record with a status, and check status on every use.
CREATE TABLE auth_factors (
id uuid PRIMARY KEY,
user_id uuid NOT NULL,
kind text NOT NULL, -- totp, webauthn, recovery, sms
label text,
revoked_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now()
);
def revoke_factor(user_id, factor_id, actor):
db.execute("UPDATE auth_factors SET revoked_at=now() WHERE id=%s AND user_id=%s",
(factor_id, user_id))
revoke_sessions_created_with(factor_id)
audit.log("factor_revoked", user_id, factor_id, actor)
notify(user_id, "An authentication factor was removed")
Let users do it themselves in settings, and give admins and support a controlled path. Revoking should also end sessions that relied on that factor.
How to test it
- Enroll a factor, revoke it, and try to authenticate with it. It must fail at once.
- Confirm sessions started with it are ended.
- Verify the audit log and notification.
Common mistakes
- Revocation that only hides the factor in the UI.
- Leaving active sessions alive.
- No way to revoke the last factor safely, so users keep a lost one.
Quick check
Should revoking the only factor lock the user out?
Require a replacement or a recovery path with identity proofing (V6.4.4), so users can act without staying exposed.