Previous: JWT Tokens
After a user signs in, the system needs more than an answer to the question, “Who is this?” It also needs to answer, “What is this user allowed to do in this project?”
Cerberus is the platform’s centralized permissions service. It manages which users can access which operations in which services, and it manages groups that can be used as part of the same access model.
The User Profiles Service retrieves this information during login and includes it in the JWT. Services then use the shared authentication library to decide whether a request can reach a particular endpoint.
Permissions
A user does not simply have a generic “administrator” or “editor” label. Permissions are assigned for specific operations in specific services.
For example, a user may be allowed to manage groups in Cerberus while also being allowed to create tasks in the Quest service:
{
"Cerberus": [
"post_group_group_name_users",
"delete_group_group_name_user_user_id"
],
"Quest": [
"get_quests",
"patch_quest_quest_id",
"post_task"
]
}
This expresses access in terms of the capabilities offered by each service.
Cerberus keeps a configured list of recognized services. Each service name is mapped to a UUID in the service configuration. When permissions are assigned, Cerberus verifies that the target service is part of this known set.
This prevents permission records from being created for arbitrary or misspelled service names.
Managing access
Cerberus provides endpoints for viewing and changing a user’s permissions:
GET /permissions/user/{user_id}
POST /permissions/user/{user_id}
DELETE /permissions/user/{user_id}
When assigning permissions, the request identifies:
- The user receiving access
- The project where the access applies
- The target service
- The operations that should be allowed
Permissions are assigned within a project. When a caller changes another user’s permissions, Cerberus verifies that the request’s Project-ID matches the project carried in the caller’s token.
Permission management is itself protected. A user must have the appropriate Cerberus permission before they can grant, change, or remove another user’s access.
The service also supports default permissions for a project. These make it possible to establish a baseline level of access and then add more specific permissions for individual users when needed.
Groups
Permissions are not always managed only person by person. Cerberus also supports groups.
A group is an entity, and membership is represented through the same link-based model used elsewhere in the system:
User ─── user_group link ─── Group
Cerberus provides operations for retrieving a user’s groups, adding users to a group, and removing users from a group.
The User Profiles Service retrieves group membership during token creation. The group information then travels with the rest of the user’s access context.
This allows services to use both direct permissions and group membership when applying access rules.
Shared authentication library
Cerberus manages permission assignments, but it does not sit in front of every request to every service.
Each service uses a shared authentication library. The library provides the validate_permissions decorator, which is applied to endpoints that need access control:
@validate_permissions("POST_PERMISSIONS_USER_USER_ID")
async def set_user_permissions_in_project(...):
...
The decorator executes before the endpoint function. It reads the service’s authorization configuration, extracts and checks a token when necessary, verifies project context, and allows or rejects the request before business logic runs.
This gives services a common enforcement mechanism while allowing each service to define its own endpoint permissions.
Endpoint configuration
Each service keeps its endpoint access rules in auth.yml.
For example, Cerberus defines:
`debug_mode: PROD
permissions:
INFO: OPEN
GET_PERMISSIONS_USER_USER_ID: OPEN
POST_PERMISSIONS_USER_USER_ID: GRANTED
DELETE_PERMISSIONS_USER_USER_ID: GRANTED
GET_GROUPS_USER_USER_ID: OPEN
POST_GROUP_GROUP_NAME_USERS: GRANTED
DELETE_GROUP_GROUP_NAME_USER_USER_ID: GRANTED`
The endpoint code identifies the operation:
@validate_permissions("POST_GROUP_GROUP_NAME_USERS")
This keeps endpoint business logic separate from access policy.
Access levels
The library recognizes three access levels:
OPEN -- No token is required
AUTHORIZED -- A valid JWT is required
GRANTED -- A valid JWT containing the required permission is required
An OPEN endpoint is available to any caller.
An AUTHORIZED endpoint requires a Bearer token that can be validated with the service’s JWT public key and configured algorithm.
A GRANTED endpoint requires a valid token and the permission associated with the endpoint. The permission can be assigned directly to the user or made available through group membership.
Request validation
The shared decorator applies the following flow:
Request
→ validate_permissions
→ resolve endpoint access level from auth.yml
→ extract token when required
→ read user context from the token
→ compare token project with request Project-ID
→ validate token or required permission
→ execute endpoint
Development and production behavior
The configuration includes a debug mode.
In development mode, an endpoint that is absent from auth.yml is treated as open. In production mode, an endpoint without an access configuration is denied.
This makes production behavior fail closed: an endpoint must be intentionally configured before it can be exposed.
Authorization can also be disabled entirely through service configuration. In that case, the decorator becomes a no-op and returns the original function without applying access checks.
Closing perspective
Cerberus provides the centralized model for permissions and groups. The shared authentication library turns that model into endpoint protection across services.
Cerberus determines which operations a user may perform. The User Profiles Service places that resolved context into a JWT. Each service uses auth.yml to classify its endpoints as open, authenticated, or permission-restricted, and validate_permissions enforces that classification before business logic runs.
This gives the platform one permission model and one access-validation mechanism while allowing each service to define the rules appropriate to its own API.
Top comments (0)