Source document · API/docs/AUTHENTICATION.md
Authentication and access control
The API issues its own signed access and refresh tokens. A successful password check alone does not create a session: email verification and sign-in use one-time codes. Protected endpoints also apply role, ownership, and workflow checks in the relevant module.
Account and session lifecycle
Registration creates an account pending email verification. Login sends a six-digit sign-in code with a 15-minute lifetime. Codes are single-use and stored hashed. Resend requests are throttled. Password recovery sends a one-time code and changes the password only after confirmation.
| Operation | Endpoint | Purpose |
|---|---|---|
| Register | POST /api/v1/auth/register | Create a member account and initiate email verification. |
| Verify email | POST /api/v1/auth/verify-email | Consume the verification code for user_id. |
| Start login | POST /api/v1/auth/login | Validate credentials and send a sign-in code. |
| Complete login | POST /api/v1/auth/login/verify | Consume the code and issue a session. |
| Refresh | POST /api/v1/auth/refresh | Rotate a refresh token and issue the next session. |
| Logout | POST /api/v1/auth/logout | Revoke the supplied refresh token. |
| Password recovery | POST /api/v1/auth/password-reset/request, then /confirm | Request and consume a reset code. |
| Current user | GET /api/v1/auth/me | Read the authenticated account. |
| Profile | PATCH /api/v1/auth/me | Change username and display name. |
| Delete account | DELETE /api/v1/auth/me | Delete the authenticated account. |
Access tokens default to 15 minutes; refresh tokens default to 30 days. Refresh tokens rotate on use and are single-use. A client should atomically replace the stored token pair after refresh and clear it on logout or an unrecoverable authentication error. The Android app encrypts its session using Android Keystore.
Authorization layers
Authentication means the API knows which account made the request. Authorization is the separate check that decides whether that account can act on a resource. Possessing a valid bearer token does not grant provider or administrator privileges.
| Actor | Typical access |
|---|---|
| Member | Their own profile, bookings, payments, notifications, conversations, and community actions. |
| Provider | Their provider profile, owned listing/menu, provider dashboard, eligible orders, and manual sales. Provider approval and listing subscription determine public listing visibility. |
| Accountant | Scoped reporting and permitted read access, based on explicit service assignments. |
| Administrator | Administrative operations such as moderation, role/status changes, payment review, provider approval, and report export. |
| Guest | Create an order without an account and read that booking only with its one-time guest access token. |
Rules are enforced per use case. For example, an order is readable by its customer, its provider, and authorized staff; only its provider owner or an administrator can perform management transitions. Payment confirmation accepts a provider or administrator where applicable; payment rejection is administrator-only. Admin routes require both a valid bearer token and the required staff role.
Guest booking capability
POST /api/v1/orders accepts either an authenticated bearer token or guest contact details. A guest omits the Authorization header and sends an Idempotency-Key; a malformed or expired bearer token returns 401 instead of silently falling back to guest mode. The server ignores client-supplied totals, provider IDs, and currencies, and derives the price from the selected active menu item. Guest creation returns a one-time access capability. The database stores its hash, not the raw token. Recover the booking with:
GET /api/v1/guest/orders/{id}
X-Guest-Access-Token: <guest-access-token>Treat this token like a password: anyone who has it can access that guest booking. Store it securely and do not place it in analytics, logs, or shared links.
The guest capability is independent of email verification and account login. It grants access only to the specific guest order and expires after 90 days. It does not grant permission to list guest orders or create payment claims as another account.
Client handling checklist
- Use HTTPS outside local development.
- Send access tokens only in the
Authorizationheader. - Keep the MailAfrica API key, database URL,
AUTH_TOKEN_SECRET, and LiveKit secret on the server. - Never treat hidden UI controls as authorization; the API owns every permission decision.
- On
401, refresh once if possible, then return to sign-in if refresh fails. On403, show that the account is authenticated but lacks permission. - Use optimistic version fields only with the latest returned resource version; reload after a
409conflict. - Do not store or reuse a guest token beyond the booking-recovery flow.