CTMS uses Role-Based Access Control (RBAC) to manage access to resources. The system consists of:
- Permissions: Define specific actions that can be performed.
- Roles: Group permissions together for easier management.
- API Clients: The oAuth clients that authenticate and receive roles.
See the CTMS CLI documentation on how to manage API clients, roles, and permissions.
Permissions define what actions can be performed within the system. They are the lowest level of access control and must be assigned to roles.
- Permissions are not assigned directly to API clients.
- Roles are the only way permissions are granted to clients.
- A single permission can be used in multiple roles.
| Permission Name | Description |
|---|---|
manage_contacts |
Grants the ability to create, edit, and delete contacts |
view_contacts |
Allows access to view contacts |
Roles are collections of permissions. Assigning a role to an API client grants them all the permissions within that role.
- Roles group multiple permissions together.
- API clients receive roles, not individual permissions.
- A single API client can have multiple roles.
| Role Name | Assigned Permissions |
|---|---|
admin |
manage_contacts, view_contacts |
viewer |
view_contacts |
API Clients represent oAuth clients that authenticate and receive roles.
- Authenticate using oAuth2 client credentials.
- Receive access via assigned roles.
- Can be enabled or disabled as needed.
- Secrets can be rotated for security.
API clients authenticate using the OAuth2 Client Credentials Flow.
After creating a client, use the following curl request to obtain an access token:
curl --user <client_id>:<client_secret> -F grant_type=client_credentials <server_prefix>/tokenThe JSON response will have an access token, such as:
{
"access_token": "<token>",
"token_type": "bearer",
"expires_in": <time_in_seconds>
}This can be used to access the API, such as:
curl --oauth2-bearer <token> <server_prefix>/ctms?primary_email=<email>This is how API endpoints are protected using the with_permission helper from ctms.permissions.
Using "delete_contact" as the example permission.
-
Import
with_permissionin your FastAPI app:from ctms.permissions import with_permission from fastapi import Depends, APIRouter from typing import Annotated
-
Protect an API route by requiring a permission (made up example):
router = APIRouter() @router.delete("/contacts/{contact_id}") def delete_contact( contact_id: int, db: Annotated[Session, Depends(get_db)], _: Annotated[bool, Depends(with_permission("delete_contact"))], ): return {"message": f"Contact {contact_id} deleted"}
- The
with_permission("delete_contact")ensures that the client making the request has thedelete_contactpermission. - If the client does not have the required permission, FastAPI returns a 403 Forbidden response.