Authorization
:::info Status
Implemented. Source: fastapi-backend/core/security.py, fastapi-backend/api/v1/endpoints/{mosques,memberships,invites,join,users}.py.
:::
This page covers person-level authorization — what an authenticated user is allowed to do. It is a different model from Device Authorization, which governs what a physical transmitter or stream player may do over MQTT — the two are not interchangeable and this system never conflates them.
Two independent axes
Azan360 checks two separate things on almost every mosque-scoped write:
- JWT role —
superadminor not. Carried directly on the token (core/security.py:require_role(["superadmin"])), checked with no database lookup. - Per-mosque admin standing — whether this user has a row in the
mosque-admins relationship for this specific mosque
(
db.is_mosque_admin(mosque_id, user_id)), checked withsecurity.require_mosque_admin(mosque_id, user). A superadmin short-circuits this check and passes for every mosque without a row.
There is no global "mosque admin" role on the JWT — admin standing is always evaluated per mosque, per request.
Mosque-admin flags
A mosque-admin row carries its own sub-permissions, not just membership in the relationship:
| Flag | Meaning |
|---|---|
is_owner | The original/primary admin for the mosque |
can_trigger | May start broadcasts/triggers for this mosque |
can_manage | May manage mosque settings/admins/devices |
security.require_can_trigger(mosque_id, user) checks can_trigger
specifically (superadmin still short-circuits) — a mosque admin added
without that flag can manage the mosque but not push the trigger button.
security.require_mosque_admin is the coarser check used by most
mosque-scoped endpoints (mosque CRUD, admins list, memberships list,
activity feed).
Membership status
A user's relationship to a mosque as a member (not an admin) is tracked
separately in memberships, with a status state machine:
pending → approved, plus rejected and banned. Full lifecycle:
Membership module.
Membership status gates:
- Playback entitlement — only an
approvedmembership contributes to who receives azaan push notifications and (per Playback Entitlement) device-level streaming rights. - What a member may edit on their own membership — only notification
toggles (
notify_azaan,notify_jummah,notify_waaz,notify_announcement); status changes are admin/superadmin-only. This split is deliberate: without it, a banned member couldPATCHtheir own membership back toapprovedand keep receiving azaan triggers.
Superadmin-only endpoints
Gated with dependencies=[Depends(security.require_role(["superadmin"]))]
at the route level (not inside the handler) — e.g. all of users.py's list/
create/update/delete-by-id endpoints. This is a stricter, all-or-nothing
gate than the per-mosque admin check above.
Self-service vs. admin-initiated membership
| Path | Who initiates | Approval |
|---|---|---|
POST /mosques/{id}/join, POST /join (join code) | The user themself | pending, unless the mosque has auto_approve_members set |
POST /mosques/{id}/memberships | A mosque admin/superadmin, enrolling a specific user directly | Always approved immediately — there is no admin-initiated pending state |
POST /invites | A mosque admin, by email/WhatsApp contact (creates the user account if needed) | approved if auto_approve requested, else pending |
See Membership module for the full request/response shapes and edge cases (e.g. inviting an already-approved member as a mosque admin).