Authentication flow
Project Zoe uses JWT for stateless authentication with an access + refresh token pair.1
Login
The client POSTs to On success the server returns an access token (short-lived) and a refresh token (long-lived).
/api/auth/login with username, password, and churchName (tenant slug).2
Authenticated requests
The client attaches the access token as a Bearer token on every API call:The global
JwtAuthGuard validates the token and injects req.user (including the resolved Tenant).3
Token refresh
When the access token expires, the client POSTs the refresh token to
/api/auth/refresh to obtain a new pair without requiring the user to log in again.4
Logout
POST
/api/auth/logout — invalidates the session on the server side.Password reset
isValidPassword().
Roles and permissions
Roles are defined per tenant and carry an array of permission strings:UserRoles join table. All permission checks are done server-side; the client receives the user’s permissions list on login and uses it to show or hide UI elements.
Hierarchy-scoped access
Permissions alone are not enough — Project Zoe also scopes data access to a user’s position in the Group Hierarchy:- A user’s home group (the group they lead or are assigned to) determines the root of the data they can see.
- Queries traverse the closure table downward from that root, so leaders automatically see all descendants without needing explicit permission per sub-group.
Public routes
Most routes require a valid JWT. Routes decorated with@Public() bypass the guard entirely:
POST /api/auth/loginPOST /api/auth/forgot-passwordPUT /api/auth/reset-password/:tokenPOST /api/registerGET /api/tenantsPOST /api/tenants/seed