Skip to content

Permissions

Composable permission-checking strategies for authorization decisions. Each checker evaluates an application-defined context against a specific Permission and returns True when granted.

PermissionChecker

PermissionChecker[PermissionCheckContext] is a Protocol that any permission-checking implementation must satisfy. The context type is provided by the application.

class PermissionChecker[PermissionCheckContext](Protocol):
    async def check(self, context: PermissionCheckContext, permission: Permission) -> bool:
        ...

Implementations may internally use synchronous logic, but must expose an async def check(...) method — callers always await the result.

CompositePermissionChecker

Combines multiple PermissionChecker[PermissionCheckContext] instances with OR logic. A check passes as soon as any inner checker approves. Returns True immediately on the first success; otherwise False after all checkers have been consulted.

checker = CompositePermissionChecker([
    my_role_checker,
    my_resource_checker,
])
result = await checker.check(context, Permission.READ)

Designing your own checkers

Applications define concrete PermissionChecker implementations that inspect their own context type. A role-based checker might look up permissions from a role-to-permission mapping:

from forging_blocks.domain.permissions import PermissionChecker

class RoleBasedChecker[PermissionCheckContext](PermissionChecker[PermissionCheckContext]):
    def __init__(self, role_map: dict[str, list[Permission]]) -> None:
        self._role_map = role_map

    async def check(self, context: PermissionCheckContext, permission: Permission) -> bool:
        roles = getattr(context, "roles", [])
        for role in roles:
            if permission in self._role_map.get(role, []):
                return True
        return False

A resource-based checker would similarly inspect resource metadata on the context object.

When to use

Use CompositePermissionChecker to combine multiple checkers when authorization depends on multiple factors — an admin role OR ownership of a document, for example. Define application-specific PermissionChecker subclasses for role-driven authorization (RBAC), resource-level access control, or any custom authorization logic.

All checkers operate on the foundation Permission type and an application-defined context, keeping the domain free of infrastructure concerns.

Related

Permissions use the Permission enum (in forging_blocks.foundation.permission). See Foundation Errors for error types.