docs: record real 'wrong password after logout' fix (verify resolves username OR email)
This commit is contained in:
@@ -37,3 +37,4 @@ Informed by MiroFish (CrowdSight engine) + the hermes-brain-and-tools CrowdSight
|
||||
- `2026-08-07-auth-gitea.md` — username login + first-time admin setup + Gitea push.
|
||||
- `2026-08-07-docker-final.md` — Docker build fix: ship prebuilt frontend/dist, no npm in image (resolves repeated `vite: not found`).
|
||||
- `2026-08-07-login-after-setup.md` — can't-login-after-setup = deployment data non-persistence, not login logic (verified).
|
||||
- `2026-08-07-login-email-fix.md` — REAL fix: verify() resolves username OR email; "wrong password" after logout→login was email-login not resolving a user.
|
||||
|
||||
37
docs/engineering-log/2026-08-07-login-email-fix.md
Normal file
37
docs/engineering-log/2026-08-07-login-email-fix.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# 2026-08-07 — BUG FOUND & FIXED: "wrong password" right after logout → login (no redeploy)
|
||||
|
||||
## Updated diagnosis (user correction)
|
||||
The failure happens **immediately** after logout → login again (NOT after a redeploy),
|
||||
so data persistence was NOT the cause. The password change is on disk.
|
||||
|
||||
## Real root cause
|
||||
`verify()` in `backend/app/auth/users.py` looked up the user **by USERNAME only**
|
||||
(`get_user_or_none(ident)`). After first-run setup sets an admin EMAIL, users naturally
|
||||
type that **email** in the login field on the next login. `verify("admin@corp.com", …)`
|
||||
found no user whose USERNAME is `admin@corp.com` → `AuthError("invalid credentials")`,
|
||||
rendered in the UI as "รหัสผ่านผิด" even though the password was correct.
|
||||
|
||||
The login route's `_login_body` claimed to "accept email as a fallback", but the fallback
|
||||
was cosmetic — it never resolved email → the stored user record.
|
||||
|
||||
## Fix (commit `…`, pushed as part of `3bc2399`)
|
||||
```python
|
||||
def verify(self, ident: str, password: str):
|
||||
user = self.get_user_or_none(ident) or self.by_email(ident)
|
||||
...
|
||||
```
|
||||
`verify` now resolves by **username OR email** (checks stored `email` field too).
|
||||
|
||||
## Evidence
|
||||
Live-server test (fresh user, not admin):
|
||||
- create → setup (set email `emtest@corp.com`, new password)
|
||||
- login by **username** + new pw → **200**
|
||||
- login by **email** + new pw → **200** (was 401 before the fix)
|
||||
=> this is exactly the user's scenario, now working.
|
||||
|
||||
Also refreshed the committed `frontend/dist` (was stale — old build without the username
|
||||
login/setup flow) so EasyPanel serves the correct SPA on deploy.
|
||||
|
||||
## Tests
|
||||
m0 / setup / e2e all pass. Backend logic confirmed on real on-disk data (scrypt hash
|
||||
changes on setup; new password accepted).
|
||||
Reference in New Issue
Block a user