Policies and Permissions Guide¶
Overview¶
Centrali uses Resource-Based Access Control (ReBAC) to manage authorization. This guide explains how policies and permissions work, and how to create custom access rules for your workspace.
Key Concepts¶
Resources¶
Resources represent entities that can be protected. Each resource has: - Name: Unique identifier (e.g., records, collections, files) - Category: Grouping for resources (workspace, billing, high_risk) - Actions: Operations that can be performed (e.g., create, retrieve, update, delete)
Policies¶
Policies define the rules for granting access. They contain: - Conditions: Logic that determines when access is granted - Effect: Either Allow or Deny - Variables: Dynamic values evaluated at runtime
Permissions¶
Permissions connect resources to policies: - Link a Resource with a Policy - Specify which Actions are allowed - Define the Priority when multiple permissions apply
Authorization Flow¶
Request → Resource Lookup → Policy Evaluation → Allow/Deny
↓
Conditions Checked:
- User groups/roles
- Path parameters
- Request metadata
System Resources¶
Centrali provides pre-configured system resources for each workspace:
Core Resources¶
| Resource | Actions | Description |
|---|---|---|
workspace | create, delete, update, retrieve, list, validate, manage | Workspace management |
workspace::users | create, delete, update, retrieve, list, validate, manage, security | User management |
workspace::groups | create, delete, update, retrieve, list, validate, manage | Group management |
workspace::roles | create, delete, update, retrieve, list, validate, manage | Role management |
billing | create, delete, update, retrieve, list, validate, manage | Billing access |
Data Service Resources¶
| Resource | Actions | Description |
|---|---|---|
structures | create, retrieve, update, list, delete, manage, validate | Schema management |
records | create, retrieve, update, list, delete, manage, validate, backup | Record operations |
smart-queries | create, retrieve, update, list, delete, manage, validate, execute | Saved queries |
compute-functions | create, retrieve, update, list, delete, manage, validate, execute | Function management |
function-triggers | create, retrieve, update, list, delete, manage, validate, execute | Trigger configuration |
drafts | retrieve, list, delete, update, validate, manage, create | Draft resources |
Storage Resources¶
| Resource | Actions | Description |
|---|---|---|
files | retrieve, list, create, delete, update, manage | File operations |
folders | retrieve, list, create, delete, update, manage | Folder management |
Notification Resources¶
| Resource | Actions | Description |
|---|---|---|
notifications | create, retrieve, list, delete | User notifications |
notification-preferences | create, retrieve, update, list, delete | Notification settings |
Other Resources¶
| Resource | Actions | Description |
|---|---|---|
search-entries | create, delete, update, retrieve, list | Search index |
analytics | create, retrieve, list | Analytics data |
scheduled-jobs | create, delete, update, retrieve, list, pause, resume, retry | Job scheduling |
realtime | subscribe, list, manage | Real-time events |
Policy Specification¶
Policies are defined using a specification format that supports complex conditions:
Basic Structure¶
{
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"conditions": [
// Condition definitions
]
}
],
"default": {
"rule_id": "Deny-Rule",
"effect": "Deny"
}
}
Condition Functions¶
Group/Role Membership¶
Check if user belongs to a group or has a role:
Boolean Check¶
Verify a boolean attribute:
String Comparison¶
Compare string values:
{
"function": "string_equal",
"attribute": "user_id",
"value": "{{@pathParamsId}}",
"metadata_key": "id",
"fromRequest": true,
"source": "path_params",
"valueKey": "id"
}
Path Matching¶
Check if a path starts with a prefix:
{
"function": "string_starts_with",
"attribute": "request_metadata",
"value": "/root/users/{{$user_id}}",
"metadata_key": "path"
}
Compound Conditions¶
Use operation to combine conditions:
{
"operation": "or",
"conditions": [
{ "function": "in_list", "attribute": "groups", "value": "workspace_administrators" },
{ "function": "in_list", "attribute": "groups", "value": "workspace_owners" }
]
}
Variables¶
Define dynamic values using variables:
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"variables": {
"userPath": {
"operation": "concat",
"parameters": {
"strings": ["/root/users/", "{{$user_id}}"]
}
}
},
"conditions": [
{
"function": "string_starts_with",
"attribute": "request_metadata",
"value": "{{@userPath}}",
"metadata_key": "path"
}
]
}
Common Policy Patterns¶
1. Administrators Only¶
Allow only workspace administrators:
{
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"conditions": [
{ "function": "in_list", "attribute": "groups", "value": "workspace_administrators" }
]
}
],
"default": { "rule_id": "Deny-Rule", "effect": "Deny" }
}
2. Any Authenticated User¶
Allow any authenticated user:
{
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"conditions": [
{ "function": "boolean_equal", "attribute": "is_authenticated", "value": true }
]
}
],
"default": { "rule_id": "Deny-Rule", "effect": "Deny" }
}
3. User's Own Resources¶
Allow users to access only their own resources (e.g., their profile, their files):
{
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"conditions": [
{
"function": "string_equal",
"attribute": "user_id",
"value": "{{@pathParamsId}}",
"metadata_key": "id",
"fromRequest": true,
"source": "path_params",
"valueKey": "id"
}
]
}
],
"default": { "rule_id": "Deny-Rule", "effect": "Deny" }
}
4. Path-Based Access¶
Allow access to files in a specific path:
{
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"variables": {
"userPath": {
"operation": "concat",
"parameters": { "strings": ["/root/users/", "{{$user_id}}"] }
}
},
"conditions": [
{
"function": "string_starts_with",
"attribute": "request_metadata",
"value": "{{@userPath}}",
"metadata_key": "path"
}
]
}
],
"default": { "rule_id": "Deny-Rule", "effect": "Deny" }
}
5. Admin OR Owner¶
Allow if user is either an admin or owner:
{
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"conditions": [
{
"operation": "or",
"conditions": [
{ "function": "in_list", "attribute": "groups", "value": "workspace_administrators" },
{ "function": "in_list", "attribute": "roles", "value": "workspace_owners" }
]
}
]
}
],
"default": { "rule_id": "Deny-Rule", "effect": "Deny" }
}
Creating Custom Resources¶
To add a custom resource via the API:
curl -X POST "https://api.centrali.io/workspace/{workspaceSlug}/api/v1/resources" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "custom-reports",
"category": "workspace",
"description": "Custom reporting resources",
"actions": ["create", "retrieve", "update", "delete", "list", "export"],
"labels": ["type=custom"]
}'
Creating Custom Policies¶
Create a policy to define access rules:
curl -X POST "https://api.centrali.io/workspace/{workspaceSlug}/api/v1/policies" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "reports::managers",
"description": "Allow managers to access reports",
"specification": {
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"conditions": [
{ "function": "in_list", "attribute": "groups", "value": "managers" }
]
}
],
"default": { "rule_id": "Deny-Rule", "effect": "Deny" }
},
"labels": ["type=custom"]
}'
Creating Permissions¶
Link a resource to a policy with specific actions:
curl -X POST "https://api.centrali.io/workspace/{workspaceSlug}/api/v1/permissions" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "custom-reports::managers",
"description": "Allow managers to manage custom reports",
"resourceName": "custom-reports",
"policyName": "reports::managers",
"actions": ["create", "retrieve", "update", "delete", "list"],
"priority": 100,
"labels": ["type=custom"]
}'
Using Authorization in Your Code¶
Backend Authorization Check¶
import { authorize } from '../utils/route_helpers';
router.get('/reports/:reportId', async (req, res) => {
const { workspaceSlug, reportId } = req.params;
// Check authorization
const auth = await authorize(
req,
res,
'retrieve', // action
workspaceSlug, // workspace
'custom-reports', // resource name
'workspace' // resource category
);
if (!auth) return; // 401 or 403 already sent
// Proceed with business logic
const report = await ReportService.get(workspaceSlug, reportId);
res.json({ success: true, data: report });
});
Passing Request Data¶
For policies that need request metadata (like path-based access):
const auth = await authorize(
req,
res,
'create',
workspaceSlug,
'files',
'workspace',
{ path: req.body.path } // Pass path for policy evaluation
);
Default Permissions¶
When a workspace is created, these permissions are automatically configured:
Administrator Permissions¶
- Full access to all workspace resources
- Manage users, groups, and roles
- Configure billing and high-risk operations
Authenticated User Permissions¶
- Read access to users list
- Manage own profile
- Access their own files
- Subscribe to real-time events
- Manage their own notification preferences
Public Permissions¶
- Retrieve avatar images
- Access support files
Troubleshooting¶
Common Issues¶
403 Forbidden - Permission Denied - Verify the user has the correct group/role membership - Check if the policy conditions match the request - Ensure the permission links the correct resource and policy
401 Unauthorized - Not Authenticated - Verify the JWT token is valid and not expired - Check the Authorization header format: Bearer {token}
Policy Not Evaluated - Ensure the resource exists in the workspace - Verify the policy is properly linked via a permission - Check for typos in resource/policy names
Debugging Authorization¶
- Check user groups: Verify the user's group membership
- Review policy conditions: Ensure conditions match the request
- Test with admin: If admin works but regular user doesn't, it's a policy issue
- Check logs: Look for authorization logs in the IAM service
Best Practices¶
- Use groups for role-based access: Assign users to groups rather than creating user-specific policies
- Follow least privilege: Grant only the minimum permissions needed
- Use descriptive names: Make policy names self-documenting (e.g.,
reports::readonly_users) - Document custom policies: Keep track of what custom policies are for
- Test thoroughly: Test both allow and deny cases
- Use priority wisely: Higher priority permissions are evaluated first
- Audit regularly: Review and clean up unused policies/permissions
Managing Resources¶
Resources represent entities that can be protected. The access routes live under /workspace/{workspace}/api/v1/access/.
List Resources¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/access/resources?page=1&pageSize=50" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"data": [
{
"id": "uuid",
"name": "custom-reports",
"category": "workspace",
"description": "Custom reporting resources",
"actions": ["create", "retrieve", "update", "delete", "list", "export"],
"labels": ["type=custom"],
"workspaceSlug": "acme",
"createdBy": "user-uuid",
"createdAt": "2026-01-15T10:00:00.000Z",
"lastUpdated": "2026-01-15T10:00:00.000Z"
}
],
"meta": { "total": 12, "page": "1", "pageSize": "50" }
}
Get a Resource¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/access/resources/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns the resource object directly.
Update a Resource¶
Use PUT for a full replacement or PATCH for a partial update:
curl -X PUT "https://auth.centrali.io/workspace/{workspace}/api/v1/access/resources/{id}" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "custom-reports",
"category": "workspace",
"description": "Updated description",
"actions": ["create", "retrieve", "update", "delete", "list", "export", "archive"]
}'
curl -X PATCH "https://auth.centrali.io/workspace/{workspace}/api/v1/access/resources/{id}" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "Only update the description"
}'
Returns the updated resource object.
Delete a Resource¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/access/resources/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content on success. Resources are soft-deleted.
Managing Policies¶
Policies define the rules for granting or denying access. The access routes live under /workspace/{workspace}/api/v1/access/.
List Policies¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/access/policies?page=1&pageSize=50" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"data": [
{
"id": "uuid",
"name": "reports::managers",
"description": "Allow managers to access reports",
"specification": { "rules": [...], "default": {...} },
"labels": ["type=custom"],
"workspaceSlug": "acme",
"createdBy": "user-uuid",
"createdAt": "2026-01-15T10:00:00.000Z",
"lastUpdated": "2026-01-15T10:00:00.000Z"
}
],
"meta": { "total": 8, "page": "1", "pageSize": "50" }
}
Get a Policy¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/access/policies/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns the policy object directly, including the full specification.
Update a Policy¶
Use PUT for a full replacement or PATCH for a partial update. System policies (those without the type=custom label) cannot be modified.
curl -X PUT "https://auth.centrali.io/workspace/{workspace}/api/v1/access/policies/{id}" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "reports::managers",
"description": "Updated policy for managers",
"specification": {
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"conditions": [
{
"operation": "or",
"conditions": [
{ "function": "in_list", "attribute": "groups", "value": "managers" },
{ "function": "in_list", "attribute": "groups", "value": "workspace_administrators" }
]
}
]
}
],
"default": { "rule_id": "Deny-Rule", "effect": "Deny" }
}
}'
The specification is validated on update. If validation fails, you receive a 400 with the validation errors.
Returns the updated policy object.
Validate a Policy Specification¶
You can validate a specification without creating or updating a policy:
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/access/policies/validate" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"specification": {
"rules": [
{
"rule_id": "Allow-Rule",
"effect": "Allow",
"conditions": [
{ "function": "in_list", "attribute": "groups", "value": "managers" }
]
}
],
"default": { "rule_id": "Deny-Rule", "effect": "Deny" }
}
}'
Response (valid):
Response (invalid):
Delete a Policy¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/access/policies/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content on success. Policies are soft-deleted.
Managing Permissions¶
Permissions connect resources to policies and define which actions are allowed. The access routes live under /workspace/{workspace}/api/v1/access/.
List Permissions¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/access/permissions?page=1&pageSize=50" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"data": [
{
"id": "uuid",
"name": "custom-reports::managers",
"description": "Allow managers to manage custom reports",
"resourceName": "custom-reports",
"policyName": "reports::managers",
"actions": ["create", "retrieve", "update", "delete", "list"],
"priority": 100,
"labels": ["type=custom"],
"workspaceSlug": "acme",
"createdBy": "user-uuid",
"createdAt": "2026-01-15T10:00:00.000Z",
"lastUpdated": "2026-01-15T10:00:00.000Z"
}
],
"meta": { "total": 15, "page": "1", "pageSize": "50" }
}
Get a Permission¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/access/permissions/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns the permission object directly. Returns 404 if not found.
Update a Permission¶
Use PUT for a full replacement or PATCH for a partial update. System permissions cannot be modified.
curl -X PUT "https://auth.centrali.io/workspace/{workspace}/api/v1/access/permissions/{id}" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "custom-reports::managers",
"description": "Updated permission description",
"resourceName": "custom-reports",
"policyName": "reports::managers",
"actions": ["create", "retrieve", "update", "delete", "list", "export"],
"priority": 100
}'
Returns the updated permission object. Returns 403 if you try to update a system permission.
Delete a Permission¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/access/permissions/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content on success. Permissions are soft-deleted.
Managing Roles¶
Roles group permissions together and can be assigned to users and service accounts. The routes live under /workspace/{workspace}/api/v1/.
Create a Role¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/roles" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "report_viewer",
"description": "Can view reports but not modify them"
}'
Response (201 Created):
{
"id": "uuid",
"name": "report_viewer",
"description": "Can view reports but not modify them",
"workspaceSlug": "acme",
"createdBy": "user-uuid",
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:00:00.000Z"
}
List Roles¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/roles?page=1&pageSize=100" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"data": [
{
"id": "uuid",
"name": "report_viewer",
"description": "Can view reports but not modify them",
"workspaceSlug": "acme",
"createdBy": "user-uuid",
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:00:00.000Z"
}
],
"meta": { "total": 5, "page": 1, "pageSize": 100 }
}
Get a Role¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/roles/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns the role object directly.
Update a Role¶
Role names are immutable after creation. You can update the description:
curl -X PUT "https://auth.centrali.io/workspace/{workspace}/api/v1/roles/{id}" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "Updated role description"
}'
Returns the updated role object. Returns 400 if you attempt to change the name.
Delete a Role¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/roles/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content on success.
Assign a Role to a User¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/users/{userId}/roles/{roleId}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 201 Created with the assignment record.
Remove a Role from a User¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/users/{userId}/roles/{roleId}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content.
List Users with a Role¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/roles/{roleId}/users?page=1&pageSize=100" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"data": [
{ "userId": "uuid", "roleId": "uuid", "workspaceSlug": "acme", "createdAt": "..." }
],
"meta": { "total": 3, "page": 1, "pageSize": 100 }
}
Get a User's Roles¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/users/{userId}/roles" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns an array of role objects assigned to the user.
Assign a Role to a Service Account¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/service-accounts/{serviceAccountId}/roles/{roleId}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 201 Created with the assignment record.
Remove a Role from a Service Account¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/service-accounts/{serviceAccountId}/roles/{roleId}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content.
List Service Accounts with a Role¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/roles/{roleId}/service-accounts" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns a paginated list of service accounts assigned to the role.
Managing Groups¶
Groups collect users and service accounts for policy evaluation. The routes live under /workspace/{workspace}/api/v1/.
Create a Group¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/groups" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "managers",
"description": "Department managers with elevated access"
}'
Response (201 Created):
{
"id": "uuid",
"name": "managers",
"description": "Department managers with elevated access",
"workspaceSlug": "acme",
"createdBy": "user-uuid",
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:00:00.000Z"
}
List Groups¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/groups?page=1&limit=50" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"data": [
{
"id": "uuid",
"name": "managers",
"description": "Department managers with elevated access",
"workspaceSlug": "acme",
"createdBy": "user-uuid",
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:00:00.000Z"
}
],
"meta": { "total": 4, "page": "1", "pageSize": "50" }
}
Get a Group¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/groups/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns the group object directly.
Update a Group¶
Group names are immutable after creation. You can update the description:
curl -X PUT "https://auth.centrali.io/workspace/{workspace}/api/v1/groups/{id}" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "Updated group description"
}'
Returns the updated group object. Returns 400 if you attempt to change the name.
Delete a Group¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/groups/{id}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content on success. Returns 404 if the group does not exist.
Add a User to a Group¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/users/{userId}/groups/{groupId}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 201 Created with the membership record.
Remove a User from a Group¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/users/{userId}/groups/{groupId}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content.
List Users in a Group¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/groups/{groupId}/users" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns an array of user membership records for the group.
Get a User's Groups¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/users/{userId}/groups" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns an array of group objects the user belongs to.
Add a Service Account to a Group¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/service-accounts/{serviceAccountId}/groups/{groupId}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 201 Created with the membership record.
Remove a Service Account from a Group¶
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/service-accounts/{serviceAccountId}/groups/{groupId}" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns 204 No Content.
List Service Accounts in a Group¶
curl "https://auth.centrali.io/workspace/{workspace}/api/v1/groups/{groupId}/service-accounts" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns an array of service account records in the group.
Access Evaluation¶
You can programmatically evaluate whether a request would be allowed without actually performing the action.
Evaluate Access¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/access/evaluate" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action": "retrieve",
"resource_name": "custom-reports",
"resource_category": "workspace",
"request_data": {}
}'
Response:
Debug Evaluation¶
For troubleshooting, use the debug endpoint to see why access was granted or denied:
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/access/evaluate/debug" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"resource": "custom-reports",
"resourceCategory": "workspace",
"action": "retrieve",
"debug": true,
"includeTrace": true
}'
Response:
{
"decision": "Allow",
"evaluation_context": { ... },
"why": {
"classification": "allowed",
"message": "Access granted via policy reports::managers"
},
"trace": [ ... ]
}
You can also evaluate as a specific service account by including a principal:
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/access/evaluate/debug" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"resource": "records",
"resourceCategory": "workspace",
"action": "create",
"principal": { "type": "service_account", "id": 42 },
"debug": true
}'
Requires security:debug permission on workspace::service-accounts.
Batch Evaluation¶
Evaluate multiple resource/action combinations in a single request:
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/access/evaluate/batch" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"principal": { "type": "service_account", "id": 42 },
"resourceNames": ["records", "files", "structures"],
"actions": ["create", "retrieve", "delete"],
"debug": true,
"pagination": { "offset": 0, "limit": 50 }
}'
Response:
{
"results": [
{
"resource": "records",
"resourceCategory": "workspace",
"action": "create",
"decision": "Allow",
"why": { "classification": "allowed", "message": "..." }
},
{
"resource": "records",
"resourceCategory": "workspace",
"action": "delete",
"decision": "Deny",
"why": { "classification": "policy_denied", "message": "..." }
}
],
"serviceAccount": { ... },
"pagination": { "offset": 0, "limit": 50, "total": 9, "hasMore": false }
}
Remediation Workflows¶
When a service account lacks access, Centrali can generate and apply fix options automatically.
Generate Remediation Options¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/access/permissions/remediation/generate" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"targetType": "service_account",
"targetId": 42,
"resource": "records",
"resourceCategory": "workspace",
"actions": ["create", "retrieve"]
}'
Response:
{
"targetInfo": { ... },
"requestedAccess": { "resource": "records", "actions": ["create", "retrieve"] },
"options": [
{
"optionId": "role_assignment_1",
"type": "role_assignment",
"description": "Assign existing role 'data_editor'",
"effort": "low",
"recommended": true,
"steps": [ ... ],
"sideEffects": [ "Also grants update and delete on records" ]
},
{
"optionId": "group_assignment_1",
"type": "group_assignment",
"description": "Add to group 'data_users'",
"effort": "low",
"recommended": false,
"steps": [ ... ],
"sideEffects": [ ... ]
},
{
"optionId": "create_new_1",
"type": "create_new",
"description": "Create minimal custom policy",
"effort": "medium",
"recommended": false,
"steps": [ ... ],
"sideEffects": []
}
],
"currentAccessStatus": { ... }
}
Preview Remediation¶
Preview what a remediation option would change before applying it:
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/access/permissions/remediation/preview" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"targetType": "service_account",
"targetId": 42,
"resource": "records",
"resourceCategory": "workspace",
"actions": ["create", "retrieve"],
"optionId": "role_assignment_1",
"option": { ... }
}'
Response:
{
"status": "preview",
"wouldCreate": [],
"wouldModify": [
{ "type": "role_assignment", "roleId": "uuid", "roleName": "data_editor" }
],
"summary": ["Would assign role 'data_editor' to service account 42"]
}
Apply Remediation¶
curl -X POST "https://auth.centrali.io/workspace/{workspace}/api/v1/access/permissions/remediation/apply" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"targetType": "service_account",
"targetId": 42,
"resource": "records",
"resourceCategory": "workspace",
"actions": ["create", "retrieve"],
"optionId": "role_assignment_1",
"option": { ... }
}'
Response:
{
"status": "success",
"created": [],
"modified": [
{ "type": "role_assignment", "roleId": "uuid", "roleName": "data_editor" }
],
"verification": {
"testResult": "Allow",
"message": "Access verified after remediation",
"testedActions": ["create", "retrieve"]
},
"errors": []
}
Pass "dryRun": true to get a preview instead of applying changes.
Cleanup Patterns¶
When tearing down test resources or cleaning up custom access control objects, follow this order to avoid broken references:
1. Remove Membership Assignments¶
Remove users and service accounts from groups and roles first:
# Remove user from group
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/users/{userId}/groups/{groupId}" \
-H "Authorization: Bearer YOUR_TOKEN"
# Remove user from role
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/users/{userId}/roles/{roleId}" \
-H "Authorization: Bearer YOUR_TOKEN"
# Remove service account from group
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/service-accounts/{saId}/groups/{groupId}" \
-H "Authorization: Bearer YOUR_TOKEN"
# Remove service account from role
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/service-accounts/{saId}/roles/{roleId}" \
-H "Authorization: Bearer YOUR_TOKEN"
2. Delete Permissions¶
Remove permissions that link resources to policies:
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/access/permissions/{permissionId}" \
-H "Authorization: Bearer YOUR_TOKEN"
3. Delete Policies¶
Remove custom policies after their permissions are deleted:
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/access/policies/{policyId}" \
-H "Authorization: Bearer YOUR_TOKEN"
4. Delete Resources¶
Remove custom resources last:
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/access/resources/{resourceId}" \
-H "Authorization: Bearer YOUR_TOKEN"
5. Delete Groups and Roles¶
Remove groups and roles after all membership is cleared:
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/groups/{groupId}" \
-H "Authorization: Bearer YOUR_TOKEN"
curl -X DELETE "https://auth.centrali.io/workspace/{workspace}/api/v1/roles/{roleId}" \
-H "Authorization: Bearer YOUR_TOKEN"
System objects cannot be deleted
Resources, policies, and permissions with system labels (without type=custom) are protected and cannot be updated or deleted. Only custom objects you have created can be removed.
Related Documentation¶
- Access Control Guide - Authentication overview
- Service Account Authentication - API access
- Workspace Context - Understanding workspaces