This guide configures LOS user profiles and password-recovery notifications. Email is the primary delivery channel; SMS can be enabled independently as a secondary channel. It covers two deliberately separate authentication owners:
- LOS-managed: the LOS owns the password and issues a single-use reset link.
- SSO-managed: Microsoft Entra ID, Google Workspace, Okta, or another approved identity provider owns the password. The LOS sends the user the configured provider recovery location; it does not reset the SSO password.
The current repository implements the API and UI workflows with in-memory demonstration users and reset records. Production deployment requires the persistence, authorization, audit, rate-limiting, and session controls listed below.
Open Team → User management to:
- Search users by name, email, role, branch, status, or authentication method.
- Open a profile and edit job title, phone, branch, operational role, or account status.
- Create an invitation as either LOS-managed or SSO-managed.
- Request account-appropriate recovery notifications over email and enabled SMS.
- Suspend a profile; suspended profiles cannot initiate an administrative reset from the UI.
The profile clearly shows who owns authentication. Changing profile metadata does not change authentication ownership.
Copy the template and keep the real .env file out of source control:
cp .env.example .envConfigure SMTP only on the API server:
APP_ENVIRONMENT=production
APP_PUBLIC_URL=https://los.your-company.example
EMAIL_DELIVERY_ENABLED=true
SMTP_HOST=smtp.your-company.example
SMTP_PORT=587
SMTP_USERNAME=los-mailer
SMTP_PASSWORD=inject-from-your-secret-manager
SMTP_FROM_EMAIL=no-reply@your-company.example
SMTP_USE_TLS=true
PASSWORD_RESET_EXPIRY_MINUTES=30Requirements:
APP_PUBLIC_URLmust be the approved HTTPS frontend origin. It becomes the base of local reset links.SMTP_PASSWORDmust be injected from a secret manager or workload secret; never use aVITE_variable.- Use a dedicated, least-privilege SMTP identity with an approved sender domain, SPF, DKIM, and DMARC configuration.
- The built-in adapter uses STARTTLS when
SMTP_USE_TLS=true. Use a provider-specific adapter if the mail service requires an HTTP API, OAuth, or implicit TLS. EMAIL_DELIVERY_ENABLED=falseselects simulation in development andskippedin production. A local reset preview is returned only by the administrator endpoint in development, never by the public endpoint.
Configure the optional SMS secondary channel on the API server:
SMS_DELIVERY_ENABLED=true
SMS_PROVIDER=generic_http
SMS_BASE_URL=https://sms-gateway.example.com/v1/messages
SMS_API_KEY=inject-from-your-secret-manager
SMS_SENDER_ID=LOSAPP
SMS_REQUEST_TIMEOUT_SECONDS=15
SMS_DLT_ENTITY_ID=registered-entity-id
SMS_DLT_TEMPLATE_ID=registered-template-idThe built-in adapter posts this provider-neutral contract to the complete SMS_BASE_URL:
{
"recipient": "+919876543210",
"message": "The single-use recovery message",
"sender_id": "LOSAPP",
"entity_id": "registered-entity-id",
"template_id": "registered-template-id"
}It authenticates with Authorization: Bearer <SMS_API_KEY>. If a gateway requires different authentication or field names, implement a provider adapter behind the same send(recipient, body) contract; do not add gateway-specific parsing to password_recovery.py.
Store live mobile numbers in E.164 format. The masked numbers in the demonstration fixtures are intentionally not deliverable. SMS_DELIVERY_ENABLED=false marks the SMS channel as skipped; it does not prevent email delivery.
For Indian delivery, complete the applicable Principal Entity, sender/header, content-template, consent, and routing requirements with the selected telecom provider before enabling production traffic. Use the currently approved template text and identifiers supplied by that onboarding process.
ENTRA_PASSWORD_RESET_URL=https://passwordreset.microsoftonline.com/
GOOGLE_PASSWORD_RESET_URL=https://accounts.google.com/signin/recovery
OKTA_PASSWORD_RESET_URL=https://your-tenant.okta.com/signin/forgot-passwordUse URLs approved by the identity administration team. The user receives the same approved destination by email and, when enabled, SMS.
sso_provider profile value |
Configuration used | LOS token created |
|---|---|---|
Microsoft Entra ID |
ENTRA_PASSWORD_RESET_URL |
No |
Google Workspace |
GOOGLE_PASSWORD_RESET_URL |
No |
Okta |
OKTA_PASSWORD_RESET_URL |
No |
| Unrecognized provider | Request is rejected until a recovery URL mapping is implemented | No |
To switch a user or tenant to another SSO provider safely:
- Complete OIDC/SAML onboarding and account-linking tests with the new provider.
- Configure and validate its tenant-specific recovery URL.
- Update the canonical provider mapping and contract tests.
- Migrate authentication ownership only through an audited administrator workflow; do not silently convert password users.
- Verify recovery email, SMS, sign-in, MFA, suspension, and deprovisioning in UAT.
- Obtain identity/security approval, deploy through the SDLC pipeline, and monitor failures.
This reset workflow does not reset an SSO password itself and never creates an LOS password for an SSO account.
Administrative reset:
curl -X POST http://localhost:8000/api/v1/users/USR-001/password-resetThe response reports only overall delivery status, per-channel status, authentication action, masked recipients, and safe development preview metadata. partial means one channel failed but another completed. This endpoint must be administrator-only in production.
Inspect safe channel configuration without returning endpoints, API keys, or SMTP credentials:
curl http://localhost:8000/api/v1/auth/password-recovery/statusPublic forgot-password request:
curl -X POST http://localhost:8000/api/v1/auth/password-reset-requests \
-H 'Content-Type: application/json' \
-d '{"email":"user@your-company.example"}'The API always returns the same accepted message for known and unknown valid addresses. Delivery runs as a background task.
Local reset confirmation:
curl -X POST http://localhost:8000/api/v1/auth/password-reset-confirmations \
-H 'Content-Type: application/json' \
-d '{
"token":"token-from-email-or-sms-link",
"new_password":"A-unique-password-2026",
"confirm_password":"A-unique-password-2026"
}'Local tokens are generated with a cryptographically secure random source, stored only as SHA-256 digests, expire after the configured interval, and are removed on first use. New local passwords are salted and hashed with scrypt. The public response never contains a reset token.
Email and SMS receive the same single-use link; using it from either channel consumes it for both. If every delivery channel fails, the newly issued token is revoked. SMS is a recovery delivery channel here, not an additional authentication factor and not proof that the requester owns the account.
Before production:
- Replace
user_fixtures.py, the in-memory password hash dictionary, and the in-memory token store with transactional database repositories and a durable TTL store. - Enforce administrator authorization, tenant/branch scope, CSRF protection where applicable, and immutable audit records for profile and reset operations.
- Rate-limit by account and source without changing the generic public response; add bot and abuse controls.
- Revoke all earlier reset records when a new local reset is issued, and invalidate active sessions after password change.
- Do not log email/SMS bodies, reset URLs, raw tokens, password values, SMTP credentials, SMS API keys, or identity-provider tokens.
- Monitor email bounce/complaint and SMS delivery/failure events without exposing account existence to the requester.
- Treat mobile-number changes as a high-risk, separately verified profile operation; account for SIM-swap and recycled-number risk.
- Validate redirect origins and use HTTPS/HSTS. Do not accept a return URL from the public reset request.
- Require MFA and provider-native recovery policies for SSO users.
- Add login verification against the persisted local password hash; the demonstration login currently accepts any syntactically valid email and non-empty password.
- Perform penetration, accessibility, recovery, concurrency, expiry, and enumeration-resistance tests before release.