ASVS 5.0 V16.3.1 requires that all authentication operations are logged, successful and unsuccessful, along with extra metadata such as the type of authentication and factors used. It is Level 2. Record every login, logout, factor challenge, reset and token issue, with enough context to spot credential stuffing and account takeover.
Why it matters
Authentication is where most account compromises start. Without logs you cannot tell a single mistyped password from a thousand attempts across different accounts, or notice that a successful login followed a burst of failures from the same address.
How to implement it
Decide the event list first:
- login success and failure
- multi factor challenge sent, passed and failed
- password reset requested and completed
- session or token created, refreshed and revoked
- logout and forced logout
- account lockout and unlock
For each event record the time, user id (or the attempted identifier), source IP, user agent, authentication method, factors used, outcome and a failure reason code. Never record the password or the one time code itself.
function logAuth(req, outcome, details) {
logger.info({
event: "auth." + outcome, // auth.success, auth.failure
user_id: details.userId ?? null,
attempted_login: details.userId ? undefined : hashIdentifier(details.login),
method: details.method, // password, passkey, sso
factors: details.factors, // ["password", "totp"]
reason: details.reason, // bad_password, expired_code, locked
ip: req.ip,
user_agent: req.get("user-agent"),
request_id: req.id,
});
}
Use the same message and timing for failures shown to the user, but keep detailed reasons in the log. For unknown accounts, log the attempt with a hash of the identifier, which lets you spot enumeration without storing guessed names in clear text.
How to test it
- Perform each flow in staging: correct login, wrong password, wrong code, reset, logout, lockout.
- Locate a log entry for each and check it has the method, factors and outcome.
- Confirm the entries contain no password or code values.
- Run a small burst of failures and verify an alert or query shows them grouped by source.
Common mistakes
- Logging failures but not successes, which hides account takeover.
- Skipping API key and token authentication.
- Logging the typed password when a user pastes it into the username field.
- Writing the event after the response, so crashes lose it.
Quick check
Should failed logins for unknown users be logged?
Yes. They show enumeration and credential stuffing. Store a hashed form of the identifier.
Which level does it belong to?
Level 2.