When designing authorization systems, one of the fundamental distinctions we need to make is between instance-level and collection-level authorization queries. Understanding this distinction is crucial for building secure and maintainable applications.
Collection-level authorization answers questions about entire types or collections of resources. These queries determine whether an actor has broad permissions across a category of resources.
- Can a user create new instances of a resource type?
- Can a user list/view all resources of a type?
- Can a user export the entire collection?
- Can a user perform batch operations?
// Definition
can('list', 'Document', { organizationId: '123' })
can('create', 'Document', { organizationId: '123' })
// Usage
assertCan('list', 'Document') // Fails - too broad
assertCan('list', 'Document', { organizationId: '123' }) // SucceedsCollection-level authorization is particularly important for:
- API endpoints that return lists of resources
- UI components that show resource indexes
- Bulk operations and exports
- Resource creation permissions
Instance-level authorization deals with permissions for specific resource instances. These queries determine whether an actor can perform operations on particular objects.
- Can a user view this specific document?
- Can a user edit this particular record?
- Can a user delete this instance?
- Can a user share this resource?
// Definition
can('read', 'Document', {
id: '456',
organizationId: '123',
ownerId: ctx.user.id
})
// Usage
assertCan('read', 'Document', {
id: '456',
organizationId: '123',
ownerId: 'user1'
})Instance-level authorization is crucial for:
- Individual resource operations
- Detail views in applications
- Update/delete operations
- Sharing and collaboration features
It's important to note that having collection-level permission doesn't automatically grant instance-level permissions, and vice versa. For example:
- A user might be able to list all documents but not read specific confidential ones
- A user might be able to read specific shared documents but not list all documents
- A user might be able to create new resources but not modify existing ones
- Be Explicit: Always explicitly define both collection and instance-level permissions
- Default to Deny: Require specific conditions for collection-level access
- Consider Performance: Cache instance-level permissions when checking collections
- Maintain Consistency: Ensure collection and instance rules don't contradict
- Document Intentions: Make it clear which level each permission rule targets
- Over-permissive Collection Access: Granting broad collection access without proper filtering
- Inconsistent Rules: Having collection rules that conflict with instance rules
- Missing Level: Implementing one level without considering the other
- Ambiguous Conditions: Not clearly specifying whether conditions apply at collection or instance level
Understanding and properly implementing both instance and collection-level authorization is fundamental to building secure applications. Always consider both levels when designing authorization rules, and be explicit about which level each rule targets.