Paperless-ngx supports object-level permissions — some resources can have explicit view and change permissions assigned to individual users or groups.
The following resources include permission fields (SecurableMixin):
documentscorrespondentsdocument_typesstorage_pathstags
When permissions are loaded, a Document (or other securable model) exposes:
| Field | Description |
|---|---|
owner |
User ID of the owner |
user_can_change |
Whether the current user can change the item |
permissions |
Full permission table |
doc = await paperless.documents(42)
print(doc.owner)
print(doc.user_can_change)
if doc.has_permissions:
print(doc.permissions.view.users) # list[int]
print(doc.permissions.view.groups) # list[int]
print(doc.permissions.change.users)
print(doc.permissions.change.groups)!!! note
doc.permissions is None unless you explicitly request the full permissions (see below).
By default, Paperless-ngx does not include the full permission table in responses.
Use the with_permissions() context manager — the flag is set automatically on entry and reset on exit, even if an exception occurs:
async with paperless.documents.with_permissions():
doc = await paperless.documents(42)
print(doc.permissions.view.users)
async for doc in paperless.documents:
print(doc.owner, doc.permissions)For cases where you need persistent control across multiple calls, the underlying property is available directly:
paperless.documents.request_permissions = True
doc = await paperless.documents(42)
print(doc.permissions)
async for doc in paperless.documents:
print(doc.owner, doc.permissions)
paperless.documents.request_permissions = FalseThe flag applies to all methods on the service (__call__, iteration, update()) until reset.
When drafting a new item, use set_permissions to assign ownership and ACLs at creation time (SecurableDraftMixin):
from pypaperless.models.types import Permissions
perms = Permissions(
view_users=[2, 3],
change_users=[2],
change_groups=[1],
)
draft = paperless.tags.draft(
name="confidential",
owner=1,
set_permissions=perms,
)
new_id = await paperless.tags.save(draft)Fetch the item, modify the permissions field, then call update().
Replace the whole permission set:
from pypaperless.models.types import Permissions
doc = await paperless.documents(42)
doc.permissions = Permissions(
view_users=[2, 3],
change_users=[2],
)
doc.owner = 1
await paperless.documents.update(doc)Or mutate in place (useful when adding/removing a single user):
async with paperless.documents.with_permissions():
doc = await paperless.documents(42)
doc.permissions.view.users.append(9)
doc.permissions.change.users.remove(3)
await paperless.documents.update(doc)class Permissions:
view: _PermissionScope # .users: list[int], .groups: list[int]
change: _PermissionScope # .users: list[int], .groups: list[int]Constructed with flat keyword arguments — only specify what you need, omitted keys default to []:
| Keyword argument | Meaning |
|---|---|
view_users |
User IDs with view permission |
view_groups |
Group IDs with view permission |
change_users |
User IDs with change permission |
change_groups |
Group IDs with change permission |
from pypaperless.models.types import Permissions
# Only specify what you need
Permissions(view_users=[2, 3], change_users=[2], change_groups=[1])
# Read individual scopes
perms = doc.permissions
perms.view.users # list[int]
perms.view.groups # list[int]
perms.change.users # list[int]
perms.change.groups # list[int]To populate permission assignments, you can enumerate users and groups:
async for user in paperless.users:
print(user.id, user.username)
async for group in paperless.groups:
print(group.id, group.name)