List Permissions
Return every permission granted to the authenticated user, together with the role that each permission comes from. Useful when a client needs to render a UI conditional on many permissions, or when you are debugging why a user can or cannot perform an action.
GET /api/v1/authz/permissions
When to Use This
- Render UI elements conditionally on the full permission set.
- Show the user what they can do on a profile or settings page.
- Capture effective permissions for audit or compliance.
- Diagnose authorization behavior — see the exact list that the server uses.
Request
Attach the user's access token; no request body is needed. The token needs the
authz:read scope (or the blanket admin scope). Request it in the authorization request
and allow it on the client. Without it, the server answers 403 forbidden with
details.required_scopes: ["authz:read"] and the token's details.granted_scopes. An
API key (lmk_) cannot hold authz:read, so it always gets this 403. See
User API scopes.
curl -X GET https://api.example.com/api/v1/authz/permissions \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response
{
"user_id": "019d6190-9bba-7b5f-a0a5-07a6d10184d2",
"permissions": [
{
"slug": "document.view",
"description": "View documents",
"source": "role:Viewer"
},
{
"slug": "document.edit",
"description": "Edit documents",
"source": "role:Editor"
},
{
"slug": "document.create",
"description": "Create new documents",
"source": "role:Editor"
},
{
"slug": "user.view",
"description": "View user profiles",
"source": "role:Admin"
},
{
"slug": "user.manage",
"description": "Manage users",
"source": "role:Admin"
}
],
"count": 5
}
Response Fields
| Field | Type | Description |
|---|---|---|
user_id | string (UUID) | ID of the authenticated user |
permissions | array | Array of permission objects |
count | integer | Total number of permissions |
data, pagination | array, object | The same list again in the envelope that every LumoAuth list endpoint uses (data holds the permission objects, pagination the page metadata) |
Permission Object
| Field | Type | Description |
|---|---|---|
slug | string | Unique permission identifier (e.g., document.edit) |
description | string | Human-readable description |
source | string | The role that granted this permission, always formatted role:<RoleName> |
The endpoint returns the user's effective permissions resolved through their
roles, including roles inherited from group membership. The source label
always names the granting role (role:<RoleName>); there is no separate
group: source. A permission granted by more than one role appears once per
granting role.
Examples
Building a Navigation Menu
async function buildNavigation() {
const response = await fetch('/api/v1/authz/permissions', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const { permissions } = await response.json();
const permSet = new Set(permissions.map(p => p.slug));
const navItems = [];
// Always show dashboard
navItems.push({ label: 'Dashboard', href: '/dashboard' });
// Conditionally show based on permissions
if (permSet.has('document.view')) {
navItems.push({ label: 'Documents', href: '/documents' });
}
if (permSet.has('user.view') || permSet.has('user.manage')) {
navItems.push({ label: 'Users', href: '/users' });
}
if (permSet.has('settings.manage')) {
navItems.push({ label: 'Settings', href: '/settings' });
}
return navItems;
}
Caching the Permission Set
class PermissionCache:
"""Cache user permissions for efficient checking"""
def __init__(self, access_token):
self.token = access_token
self._permissions = None
def load(self):
"""Fetch and cache all permissions"""
response = requests.get(
f'{LUMOAUTH_URL}/api/v1/authz/permissions',
headers={'Authorization': f'Bearer {self.token}'}
)
data = response.json()
self._permissions = {p['slug'] for p in data['permissions']}
return self._permissions
def has(self, permission):
"""Check if user has a permission"""
if self._permissions is None:
self.load()
return permission in self._permissions
def has_any(self, permissions):
"""Check if user has any of the permissions"""
if self._permissions is None:
self.load()
return bool(self._permissions & set(permissions))
# Usage
perms = PermissionCache(access_token)
if perms.has('document.delete'):
delete_document(doc_id)
When you only need a handful of specific permissions for a page, use
/api/v1/authz/check-bulk instead of downloading the full list.
System permissions you will see
Besides the permissions that you define, every organization is seeded with system permissions. They appear in this endpoint like any other slug. The ones that matter for AI-agent features:
| Slug | Grants | Held by default |
|---|---|---|
jit.approve | Approve or deny just-in-time permission requests raised by agents (portal inbox, REST, mobile, approval channels). The agent's owner and the on-behalf-of user are still refused for their own requests. | Organization admins |
agents.view | See the agent list, agent policies and security-signals pages | Organization admins |
agents.create / agents.edit / agents.delete | Register, change (including creating and toggling access policies) and remove agents | Organization admins |
policies.view / policies.create / policies.edit / policies.delete | Manage AI policies | Organization admins |
settings.manage | Authentication and security policy plus organization infrastructure (API keys, custom domains, integrations), including security-signal streams and receivers and approval channels. It is not a blanket admin grant. | Organization admins |
authz.check | Ask authorization questions about other subjects: check, AuthZEN (the standard "may this subject do this action on this resource?" API), Zanzibar check and expand | Organization admins |
jit.approve, the agents.* and policies.* write permissions (create, edit,
delete) and settings.manage count as admin-equivalent. A role that grants any
of them is treated like a system role for assignment safety. To let someone review agent requests without making
them an admin, create a role that grants only jit.approve. See
Who can approve.
An agent authenticated with an agk_ API key or an agent access token can call
/api/v1/authz/check* for its own subject. Those credentials are stateless and
are accepted only on agent, JIT and authz-check routes. See
Agent API keys.
Related
- Permission Checks — single, bulk, any, and all checks.