Authentication
Dual authentication strategy: session/cookie for web admin, JWT for mobile apps. Phone OTP is the primary authentication method for customers.
Customer Authentication Flow
Customers authenticate using their phone number. OTP is the primary method, with PIN as a faster returning-user shortcut.
First-time Customer Login
Returning Customer Login
Or use OTP flow again (always available as fallback)
- Phone number is the primary identifier (Saudi format:
05XXXXXXXX, 10 digits) - OTP: 6-digit code, 5-minute expiry, delivered via WhatsApp (primary) or SMS (fallback)
- PIN: 6-digit numeric, set after first successful OTP verification
- Returning users can use PIN directly for faster login without waiting for an OTP
Admin / Field Manager Authentication Flow
Admin and field manager users authenticate via traditional email and password, receiving a server-side session cookie.
Admin & FM Login
assigned_field_ids. This is enforced at the middleware level — every query is automatically filtered to only include their assigned fields. This is not a UI-level restriction; it is server-enforced.
Dual Token Strategy
The system uses two authentication mechanisms to serve different client types.
| Strategy | Used By | Mechanism | Timeout |
|---|---|---|---|
| Session / Cookie | Web Admin | Server-side session, HTTP-only cookie | 24h inactivity |
| JWT | Mobile Apps | Bearer token in Authorization header | 24h inactivity, refresh mechanism |
Rate Limiting
Rate limits protect against brute-force attacks and abuse of the OTP delivery system.
| Rule | Limit | Window |
|---|---|---|
| OTP send per phone | 3 requests | 15 minutes |
| OTP send global | 10 requests | 1 minute |
| OTP verify attempts | 5 attempts | Per code |
| PIN verify attempts | 10 attempts | Then lockout |
| Login attempts per IP | 20 attempts | 15 minutes |
PIN Lockout
The lockout is recorded in the login_attempts table for security auditing. Admins can view lockout history in the admin dashboard to identify potential attack patterns.
JWT Token Lifecycle
- Access token: 24h expiry, refreshable before expiration
- Refresh token: 30d expiry, used to obtain a new access token without re-authentication
- Inactivity reset: On each API request with a valid token, the inactivity timer resets — active users are never forced to re-login
- Token payload contains:
user_id,role,assigned_field_ids(for FM scoping)
assigned_field_ids so the API can filter queries without an extra database lookup on every request. If field assignments change, the FM must re-authenticate to get a new token with updated field IDs.
Security Considerations
Password Hashing
All passwords hashed with bcrypt (cost factor 12). Never stored in plaintext.
OTP Storage
OTP codes are stored hashed, not in plaintext. Even if the database is compromised, codes cannot be extracted.
Session Tokens
Session tokens are cryptographically random with sufficient entropy to prevent guessing or enumeration.
Transport Security
HTTPS required for all endpoints. No HTTP fallback. CORS configured for known origins only.