Skip to content

Commit cc3ba80

Browse files
aspiersclaude
andcommitted
docs(changeset): trim OTP-logging changeset to operator essentials
The changeset had grown to PR-description depth — a verbatim sample log line, brute-forcing rationale, the wrong-vs-no-code caveat, and a full per-endpoint enumeration. None of it is something an operator acts on. Cut to three scannable bullets: the fields and reasons on each line, the info/warn split, and that no LOG_LEVEL change is needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent a7f3e68 commit cc3ba80

1 file changed

Lines changed: 5 additions & 10 deletions

File tree

.changeset/log-otp-verification-failures.md

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@
22
'ePDS': patch
33
---
44

5-
Failed sign-in code entries now show up in the server logs, split by reason and tagged with the account's email address.
5+
Failed sign-in code attempts now appear in the server logs, split by reason and tagged with the account's email.
66

77
**Affects:** Operators
88

9-
**Operators:** these failures come from the browser posting straight to `/api/auth/sign-in/email-otp`, which the auth service mounts with no request logging, so until now they were invisible.
9+
**Operators:** failed OTP verifications are now logged under the `auth:better-auth` logger.
1010

11-
- Each failure is logged under the `auth:better-auth` logger name (all levels are visible at the default `info` level, no `LOG_LEVEL` change needed). The log message is self-contained and distinct per reason, so you can tell the failures apart at a glance without inspecting a separate field:
12-
- `OTP verification failed: code expired` — logged at `info` (routine user error)
13-
- `OTP verification failed: invalid or unrecognized code` — logged at `info` (routine user error)
14-
- `OTP verification failed: too many attempts, code invalidated` — logged at `warn`, since repeated wrong codes can signal brute-forcing rather than a fumble
15-
- Each line carries three fields, ordered for debugging a specific failure: `email` (the account that failed), `statusCode` (`400`, or `403` for too-many-attempts), and `path` (the endpoint). In Railway's log view a line reads e.g. `[INFO] OTP verification failed: code expired email="user@example.com" statusCode=400 path="/sign-in/email-otp"`.
16-
- Counting `code expired` vs `invalid or unrecognized code` over time separates users whose code genuinely lapsed (late email delivery) from users retyping a stale code, so a rise in `code expired` points at delivery delay rather than user error. Note that `invalid or unrecognized code` covers both a wrong code and no pending code for that email — the two are not distinguished.
17-
- The same logging also covers the other OTP _verification_ endpoints (`/email-otp/check-verification-otp`, `/email-otp/verify-email`, `/email-otp/reset-password`); the `path` field identifies which one. The OTP _send_ endpoints (`/email-otp/send-verification-otp`, `/email-otp/request-password-reset`) are deliberately excluded — a failure there is not a verification failure. Only these verification endpoints are logged.
18-
- Only 4xx errors are logged here; 3xx redirects are filtered out and 5xx errors are already logged by the framework, so this adds no duplicate 5xx noise.
11+
- Each line carries an `email`, `statusCode`, and `path` field, and names the reason: `code expired`, `invalid or unrecognized code`, or `too many attempts, code invalidated`.
12+
- Routine failures (expired / invalid) log at `info`; too-many-attempts logs at `warn`.
13+
- All are visible at the default `info` level — no `LOG_LEVEL` change needed.

0 commit comments

Comments
 (0)