Permission Checks
These endpoints answer RBAC-style (role-based access control) questions: "does the authenticated user have permission X?". All variants take a permission slug (or a list) and an optional context object. The optional context lets the server bring ABAC (attribute-based access control: rules over properties of the user, the resource and the request) policies into the decision — for example, checking document.edit with {document_owner_id: 123} in context can evaluate ownership conditions alongside the role check.
Single Permission Check
POST /api/v1/authz/check
Return whether the authenticated user has a single permission.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
permission | string | Yes | Permission slug (e.g., document.edit) |
context | object | No | Contextual attributes for ABAC evaluation |
Simple Check
curl -X POST https://api.example.com/api/v1/authz/check \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"permission": "document.edit"
}'
{
"allowed": true,
"permission": "document.edit",
"user_id": "019d6190-9bba-7b5f-a0a5-07a6d10184d2"
}
Check with Context (ABAC)
Include attributes about the target resource, request, or environment so ABAC policies can evaluate dynamic conditions.
curl -X POST https://api.example.com/api/v1/authz/check \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"permission": "document.edit",
"context": {
"document_id": 456,
"document_owner_id": 123,
"department": "engineering"
}
}'
Context is how you pass per-request facts — resource IDs, ownership, IP, device type, timestamps — that policies can reference. Attributes stored on the user or resource are merged with context at evaluation time.
Checking Another Subject
All four check endpoints accept an optional subject object. Without it, the check is about the caller. With it, you can ask about another user or agent in the same organization — but only if the caller holds the authz.check permission or presents a token / API key with the authz:check scope. See Who May Ask About Whom.
| Field | Type | Required | Description |
|---|---|---|---|
subject.type | string | Yes (when subject is present) | user or agent |
subject.id | string | Yes (when subject is present) | User UUID or agent id (agt_…) |
curl -X POST https://api.example.com/api/v1/authz/check \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"permission": "document.edit",
"subject": {"type": "user", "id": "019d6190-9bba-7b5f-a0a5-07a6d10184d2"}
}'
The response's subject_id / user_id then identify the requested subject, not the caller.
| Status | Meaning |
|---|---|
403 insufficient_permissions | The subject is not the caller and the caller lacks authz.check / authz:check |
404 SUBJECT_NOT_FOUND | No such user/agent in the caller's organization (only reachable with the privilege) |
400 INVALID_SUBJECT | subject is present but not {type: "user" | "agent", id} |
Bulk Permission Check
POST /api/v1/authz/check-bulk
Check many permissions in one request. The response contains an individual result for each permission. This is the efficient way to populate a page that conditionally shows several actions.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
permissions | array | Yes | Array of permission slugs to check |
context | object | No | Shared context for all checks |
Example
curl -X POST https://api.example.com/api/v1/authz/check-bulk \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"permissions": ["document.view", "document.edit", "document.delete", "document.share"],
"context": {
"document_id": 456
}
}'
{
"results": {
"document.view": true,
"document.edit": true,
"document.delete": false,
"document.share": true
},
"user_id": "019d6190-9bba-7b5f-a0a5-07a6d10184d2",
"context": {
"document_id": 456
}
}
Check Any (OR)
POST /api/v1/authz/check-any
Return allowed: true if the user has at least one of the listed permissions. Useful when multiple permissions can unlock the same feature.
curl -X POST https://api.example.com/api/v1/authz/check-any \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"permissions": ["document.owner", "document.editor", "admin.all"]
}'
{
"allowed": true,
"permissions": ["document.owner", "document.editor", "admin.all"],
"user_id": "019d6190-9bba-7b5f-a0a5-07a6d10184d2"
}
Check All (AND)
POST /api/v1/authz/check-all
Return allowed: true only if the user has every listed permission. Use for actions that require compound authority.
curl -X POST https://api.example.com/api/v1/authz/check-all \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"permissions": ["document.edit", "document.publish"]
}'
{
"allowed": false,
"permissions": ["document.edit", "document.publish"],
"user_id": "019d6190-9bba-7b5f-a0a5-07a6d10184d2"
}
Response Fields
| Field | Type | Description |
|---|---|---|
allowed | boolean | Whether the permission check passed |
permission | string | The permission that was checked (single check) |
permissions | array | The permissions that were checked (any/all) |
results | object | Map of permission → result (bulk check) |
subject_type / subject_id | string | The subject the decision is about (user or agent) — the caller unless a subject was supplied |
user_id | string (UUID) | Same as subject_id for user subjects (kept for backwards compatibility) |
context | object | The context that was provided (empty object {} if none) |
Common Patterns
UI Button Visibility
// Fetch permissions when loading a document editor
async function loadDocumentPermissions(documentId) {
const response = await fetch('/api/v1/authz/check-bulk', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
permissions: ['document.edit', 'document.delete', 'document.share'],
context: { document_id: documentId }
})
});
const { results } = await response.json();
// Show/hide UI elements based on permissions
document.getElementById('edit-btn').hidden = !results['document.edit'];
document.getElementById('delete-btn').hidden = !results['document.delete'];
document.getElementById('share-btn').hidden = !results['document.share'];
}
Server-Side Guard
# Check permission before processing request
def require_permission(permission):
def decorator(func):
def wrapper(*args, **kwargs):
response = requests.post(
f'{LUMOAUTH_URL}/api/v1/authz/check',
headers={'Authorization': f'Bearer {get_token()}'},
json={'permission': permission}
)
if not response.json().get('allowed'):
raise PermissionDenied(f'Missing permission: {permission}')
return func(*args, **kwargs)
return wrapper
return decorator
@require_permission('document.delete')
def delete_document(document_id):
# User has permission, proceed with deletion
...
Related
- List Permissions — return the full permission set for the current user.
- Zanzibar Checks — relationship-based checks for hierarchical resources.