Document-Level Security
Document-Level Security (DLS) automatically injects filters into queries based on the authenticated user's role. This ensures users only see documents they are authorized to access without application-level enforcement.
Implementation is in services/storage-engine/src/security/dls.rs.
Policy Model
A DLS policy defines a filter that is applied to all queries matching a specific database, collection, and user role:
{
"id": "policy_001",
"database": "mydb",
"collection": "documents",
"role": "authenticated",
"filter": "{\"owner_id\": {\"$eq\": \"$auth.user_id\"}}",
"enabled": true
}
| Field | Description |
|---|---|
database | Target database name |
collection | Target collection name |
role | User role this policy applies to |
filter | JSON filter with $auth.* variable placeholders |
enabled | Whether the policy is active |
Auth Variable Resolution
Filters can reference the authenticated user's properties using $auth.* variables. These are resolved at query time from the JWT claims:
| Variable | Resolved To |
|---|---|
$auth.user_id | Authenticated user's ID |
$auth.email | Authenticated user's email |
$auth.role | Authenticated user's role |
Example
Policy filter:
{"owner_id": {"$eq": "$auth.user_id"}}
For a user with ID usr_abc123, the resolved filter becomes:
{"owner_id": {"$eq": "usr_abc123"}}
Filter Injection
The DLS middleware reads the AuthContext from the request, looks up matching policies for the target database and collection, resolves $auth.* variables, and injects the merged filter via the X-DLS-Filter header. The CRUD handler merges this with any user-supplied filter using $and.
Multiple Policies
When multiple policies match the same request, they are merged with $and:
{
"$and": [
{"owner_id": {"$eq": "usr_abc123"}},
{"department": {"$eq": "engineering"}}
]
}
Service Role Bypass
Requests authenticated with a service role API key bypass DLS entirely. This allows administrative operations and background jobs to access all documents without restriction.
# Service role - no DLS filtering
// Service role connections bypass DLS
mongosh "mongodb://service-user:password@localhost:27017"
// Authenticated user connections have DLS filters applied
mongosh "mongodb://alice:password@localhost:27017"
CRUD Examples
Users See Only Their Documents
Policy:
{
"database": "mydb",
"collection": "notes",
"role": "authenticated",
"filter": "{\"user_id\": {\"$eq\": \"$auth.user_id\"}}"
}
When Alice (user ID usr_alice) queries:
// Alice connects via MongoDB driver
mongosh "mongodb://alice:password@localhost:27017/mydb"
db.notes.find()
The query is executed with filter: {"user_id": {"$eq": "usr_alice"}}.
Team-Based Access
Policy:
{
"database": "mydb",
"collection": "projects",
"role": "authenticated",
"filter": "{\"team_members\": {\"$in\": [\"$auth.email\"]}}"
}
This restricts each user to projects where their email appears in the team_members array.
Inserts and Updates
DLS filters apply to all operations, not just reads. An update targeting documents outside the user's DLS scope will match zero documents.
Source of Truth
- DLS engine:
services/storage-engine/src/security/dls.rs - Security module:
services/storage-engine/src/security/