Unify doctor/patient auth in existing routes with first-time password flow
This MR consolidates and hardens authentication for doctors/staff and patients using existing auth routes only.
Scope
- Extends POST /api/v1/auth/login to support:
- Doctor/staff login via phone_no + password
- Patient login via book_no + password
- Extends POST /api/v1/auth/forgot-password for:
- Normal forgot-password reset
- Patient first-time password setup
- Doctor first-time password setup
- Keeps route structure unchanged (no new auth endpoints).
Key Changes
- Unified login flow in existing /auth/login:
- Conditional identifier validation:
- phone_no XOR book_no (not both, not neither)
- First-time login handling when DB password is NULL:
- Returns structured response (first_time_login, create_password for doctor/staff)
- No JWT issued
- JWT issued only after successful password validation
- Prevents verify_password() on NULL stored password
- Conditional identifier validation:
- Forgot-password flow enhancements in existing /auth/forgot-password:
- Optional request schema fields with manual, flow-specific validation in route
- Supports phone_no/new_password aliases for compatibility
- Validates patient book_no + phone_no matching where applicable
- Reuses existing OTP/password reset service logic (extended, not replaced)
- OTP/dev testing improvements in /auth/send-otp:
- Fixed async/sync bug (await removed for sync SMS sender)
- Logs generated OTP to backend logs for developer visibility
- Adds dev-mode OTP response (otp included only in development/dev/local/test)
- Adds SMS-config bypass for dev when provider credentials are missing:
- OTP still generated/stored
- Success response still returned
- Swagger/OpenAPI usability:
- Added request-body examples for login/forgot-password flows (dropdown examples)
- Service hardening:
- authenticate_user() requires password and safely handles null stored password
Security/Behavior Guarantees
- No token generation when:
- password is missing
- password is incorrect
- stored password is NULL (first-time flow)
- Production-safe OTP response behavior:
- OTP is not returned in response outside dev-like environments
Backward Compatibility
- Existing auth endpoints retained
- Existing forgot-password flow retained and extended
- Added field aliases to reduce client-side breakage (phone_no, new_password)
Quality
- Ruff lint + format checks pass for all touched files
- Auth route/service tests updated for new flow coverage (plus explicit mixed-outcome tests as requested)
Based on the latest review updates, the authentication system has been modified to support login using either a phone number or a book number for all users.
Background:
A new feature was introduced where a unique book number (book_no) is automatically generated and assigned to every user during signup. This means all users in the system — including doctors, admins, volunteers, and patients — now have a book number associated with their account.
Because of this change, the login flow needed to be updated so that users can authenticate using either their phone number or their book number along with their password.
Changes Implemented:
- Updated the
/api/v1/auth/loginendpoint to support two authentication methods:- phone_no + password
- book_no + password
- The login logic now dynamically determines which identifier is provided and fetches the user accordingly.
- Validation rules were added to ensure correct input handling:
- Either
phone_noorbook_nomust be provided. - Both cannot be provided at the same time.
- If neither identifier is provided, a validation error is returned.
- Either
- Password verification is performed only after the user is successfully identified using the provided identifier.
- JWT access tokens are generated only after successful password validation.
- The change applies to all user roles (doctor, admin, volunteer, patient) since every user now has a
book_no. - No changes were made to the existing signup flow.
- The previously implemented forgot-password functionality remains unchanged and continues to work with the current authentication structure.
Result:
Users can now log in using either their phone number or their book number along with their password, providing more flexibility while maintaining secure authentication logic. The login endpoint now supports a unified authentication flow for all user roles without introducing new API routes or breaking existing functionality.