Skip to content

feat/ update-user-contact#36

Merged
Rashed99Azm merged 1 commit into
developfrom
feat/update-user-contact-info
May 26, 2026
Merged

feat/ update-user-contact#36
Rashed99Azm merged 1 commit into
developfrom
feat/update-user-contact-info

Conversation

@Rashed99Azm
Copy link
Copy Markdown
Collaborator

Summary

  • Fixed critical auth hijacking bug: DevAuthHandler was unconditionally overriding real JWT tokens with the dev-mode cookie, causing all authenticated requests to resolve to the deterministic dev user account. Now DevAuthHandler prioritizes real JWT validation (from /api/auth/login) and only falls back to dev-mode cookie when no valid JWT is present.
  • Added OTP ownership validation: OtpVerification was not storing UserId, so contact-change confirmations could not verify the OTP belonged to the authenticated user. Added nullable UserId to OtpVerification, scoped FindActiveAsync by user, and added ownership checks in both ConfirmEmailChange and ConfirmPhoneChange handlers.
  • Fixed email change persistence bug: ConfirmEmailChange was mutating Email/UserName/NormalizedEmail directly, leaving the old NormalizedEmail in the database. Now uses UserManager.SetEmailAsync and UserManager.SetUserNameAsync to ensure Identity-managed fields stay consistent.
  • Seeded missing email/phone change OTP templates: Added EMAIL_CHANGE_OTP (Email channel) and PHONE_CHANGE_OTP (Sms channel) to ReferenceDataSeeder so RequestEmailChangeCommandHandler and RequestPhoneChangeCommandHandler can resolve their dedicated templates correctly.
  • Added database-level duplicate account prevention: Added a filtered unique index on NormalizedEmail to prevent duplicate accounts at the database level. Added UserId composite index on otp_verifications to support scoped OTP lookups.

Test plan

  1. Login with real account via /api/auth/login — JWT sub claim must match real User.Id
  2. Call /api/me — must return real account, NOT dev account (aaaaaaaa-aaaa-aaaa-aaaa-000000000005)
  3. Request email change (/api/me/email/request-change) → OTP sent via EMAIL_CHANGE_OTP template
  4. Confirm email change (/api/me/email/confirm-change) → /api/me should show new email
  5. Old email login should fail; new email login should succeed
  6. Request phone change (/api/me/phone/request-change) → OTP sent via PHONE_CHANGE_OTP template
  7. Confirm phone change (/api/me/phone/confirm-change) → phone updated on real account

Security checklist

  • No new secrets / credentials in code
  • AuthN / AuthZ impact considered — Fixed auth hijacking where dev cookie overrode real JWT. Added OTP ownership validation preventing cross-user contact-change confirmation.
  • Input validation on new endpoints — No new endpoints; existing handlers now validate otp.UserId == request.UserId
  • Audit-log entry for new state-changing operations — Email/phone changes still audited via [Audited] on User entity and OtpVerification

BRD traceability

n/a

Screenshots / output (optional)

Build output:
Build succeeded.
0 Warning(s)
0 Error(s)

… persistence, add unique email constraint

OTP Ownership & Security:
- Add UserId to OtpVerification entity (nullable, for anonymous registration flows)
- Pass recipientUserId through ContactChangeOtpService into OTP create/refresh
- Add user-scoped FindActiveAsync overload in OtpVerificationRepository to prevent contact-level collisions
- Add OTP ownership validation in ConfirmEmailChange and ConfirmPhoneChange handlers
- Use entity.UserId in VerifyOtpCommandHandler with fallback to contact lookup for anonymous flows
Email/Phone Change Fixes:
- Use UserManager.SetEmailAsync + SetUserNameAsync in ConfirmEmailChange instead of raw property mutation (fixes stale NormalizedEmail)
- Use UserManager for phone change confirmation with ownership validation
Duplicate Account Prevention:
- Add filtered unique index on NormalizedEmail to prevent duplicate accounts at DB level
- Create EF migration: AddOtpVerificationUserId (adds user_id column + composite index + unique email index)
@Rashed99Azm Rashed99Azm merged commit 7c5c9e0 into develop May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants