|
2 | 2 | 'ePDS': patch |
3 | 3 | --- |
4 | 4 |
|
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. |
6 | 6 |
|
7 | 7 | **Affects:** Operators |
8 | 8 |
|
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. |
10 | 10 |
|
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