users MongoDB collection.
The auth and user logic lives in the API service’s auth and users routes, JWT module, dependency helpers, and user model.
JWT
The JWT module signs an HS-family JWT withsettings.jwt_secret/jwt_algorithm:
| Claim | Value |
|---|---|
sub | user email |
role | role string |
name | display name |
exp | now + jwt_expire_minutes |
get_current_user dependency decodes the bearer token, then re-reads the user from MongoDB on every request — so a deactivated or deleted user is rejected immediately even with a still-valid token. The role used for authorization comes from the database record, not the token claim.
Login & self-service
Under/api/v1/auth:
| Method | Path | Auth | Purpose |
|---|---|---|---|
POST | /login | none | Email + password → access_token. 401 on bad credentials or is_active=false. |
POST | /register | admin+ | Create a user (rank-gated, see below) |
GET | /me | any | Current profile |
PUT | /me | any | Update own name |
PUT | /me/password | any | Change own password (verifies current) |
hash_password/verify_password); raw passwords are never stored.
Role hierarchy
ROLE_RANK:
| Role | Rank | Typical use |
|---|---|---|
agent | 0 | Agent Desk operator |
supervisor | 1 | Monitors/barge, Agent Assist manager |
admin | 2 | Manage bots, campaigns, users |
super_admin | 3 | Carriers, integrations, delete users |
require_admin (admin or super_admin), require_super_admin (exact), require_agent_or_supervisor, require_supervisor, require_agent_assist_manager (admin/super_admin/supervisor), require_any_role.
The same-rank rule
The guard differs between creating/assigning a role and modifying an existing user:- Create / assign role (
register, role change inupdate_user): blocked only whenactor_rank < new_rank. A user may create or promote up to their own rank — e.g. asuper_admincan mint anothersuper_admin. - Modify another user (
_check_hierarchy, used by update/deactivate/reset-password): requiresactor_rank > target_rank(actor_rank <= target_rankis rejected). You cannot modify a peer or someone above you. - Self-modification is always allowed past
_check_hierarchy(the email-equality short-circuit), but you cannot delete or deactivate yourself.
User CRUD
Under/api/v1/users:
| Method | Path | Role | Notes |
|---|---|---|---|
GET | “ | admin | List users |
GET | /{user_id} | admin | Get user |
PUT | /{user_id} | admin | Update (hierarchy + role-rank guards; email uniqueness enforced) |
DELETE | /{user_id} | super_admin | Delete (cannot delete self) |
POST | /{user_id}/deactivate | admin | Toggle is_active (cannot deactivate self) |
POST | /{user_id}/reset-password | admin | Set new password (hierarchy-gated) |
departments, max_concurrent_calls, agent_languages, agent_primary_language) are normalised on write via normalise_agent_languages/normalise_agent_primary_language. Invalid user_id → 400; missing → 404.
Related docs
API keys
Non-JWT auth for CRM-triggered dialout.
Agent Desk
Where agent/supervisor roles are used at runtime.
Agent Assist
Assist-moment management (manager roles).
CXB API overview
Control-plane responsibilities.