Role hierarchy
From least to most privileged:partner can do everything a user can do, plus additional listing and application management actions.
What each role can do
- anonymous
- user
- partner
- jurisdictionAdmin
- supportAdmin
- admin
Unauthenticated (not logged in) requests.
- Read (browse) all published listings
- Submit new applications to listings
- Read jurisdiction data
- Read multiselect questions (preferences and programs)
- Read agency data
Most read-only public-facing data is accessible without any credentials. You only need to authenticate to manage resources or access private data.
How permission checks work
Every protected endpoint runs two layers of guards before the request handler executes.1. JwtAuthGuard
Verifies theaccess-token cookie contains a valid, unexpired JWT. If the token is missing or invalid, the request returns 401 Unauthorized before any permission check occurs.
Endpoints using OptionalAuthGuard skip this rejection for unauthenticated requests — the user is simply treated as anonymous, and the request proceeds.
2. PermissionGuard
After identity is established,PermissionGuard checks whether the user’s role is permitted to perform the requested action on the requested resource type.
The action is inferred automatically from the HTTP method:
| HTTP method | Permission action |
|---|---|
GET | read |
POST | create |
PUT / PATCH | update |
DELETE | delete |
@PermissionAction decorator (for example, a POST endpoint that performs a read action).
admin users bypass the permission check entirely and are granted access to all endpoints.
Attribute-based checks (ABAC)
For resource-level ownership checks — such as ensuring auser can only read or update their own application — Casbin evaluates attribute expressions at request time.
For example, the policy rule for a user reading an application is:
r.sub is the authenticated user’s ID and r.obj.userId is the owner field on the loaded resource. If they don’t match, the request returns 403 Forbidden.
This ABAC check runs inside the service handler after the resource is loaded from the database — not in a guard — because the resource must be fetched first.
Permission policy reference
The full policy is defined inpermission_policy.csv. The format of each rule is:
g lines:
listings
listings
| Role | Allowed actions |
|---|---|
anonymous | read |
admin, supportAdmin | all actions |
applications
applications
| Role | Condition | Allowed actions |
|---|---|---|
anonymous | — | submit |
user | — | submit |
user | r.sub == r.obj.userId | read |
admin, supportAdmin | — | all actions |
users
users
| Role | Condition | Allowed actions |
|---|---|---|
anonymous | — | create |
user | r.sub == r.obj.id | read, update |
admin | — | all actions |
jurisdictions
jurisdictions
| Role | Allowed actions |
|---|---|
anonymous | read |
jurisdictionAdmin, supportAdmin | read |
admin | all actions |
feature flags
feature flags
| Role | Allowed actions |
|---|---|
admin | all actions |
admin only — no other role can read or write feature flags via the API.AMI charts, unit types, unit rent types
AMI charts, unit types, unit rent types
| Role | Allowed actions |
|---|---|
partner | read |
jurisdictionAdmin and above | all actions |
admin | all actions |
Special-purpose guards
| Guard | Purpose |
|---|---|
OptionalAuthGuard | Allows both authenticated and unauthenticated requests. Authenticated users get their role; unauthenticated requests proceed as anonymous. |
ApiKeyGuard | Checks for a valid API_PASS_KEY header. Applied at the controller level on most endpoints as a first line of defense. |
AdminOrJurisdictionalAdminGuard | Restricts access to users who are either admin or jurisdictionAdmin. |
UserProfilePermissionGuard | Enforces that a user can only access or modify their own profile. |