Initial commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
---
|
||||
title: Use @request Context in API Rules
|
||||
impact: CRITICAL
|
||||
impactDescription: Enables dynamic, user-aware access control
|
||||
tags: api-rules, security, request-context, authentication
|
||||
---
|
||||
|
||||
## Use @request Context in API Rules
|
||||
|
||||
The `@request` object provides access to the current request context including authenticated user, request body, query parameters, and headers. Use it to build dynamic access rules.
|
||||
|
||||
**Incorrect (hardcoded or missing auth checks):**
|
||||
|
||||
```javascript
|
||||
// No authentication check
|
||||
const collection = {
|
||||
listRule: '', // Anyone can see everything
|
||||
createRule: '' // Anyone can create
|
||||
};
|
||||
|
||||
// Hardcoded user ID (never do this)
|
||||
const collection = {
|
||||
listRule: 'owner = "specific_user_id"' // Only one user can access
|
||||
};
|
||||
```
|
||||
|
||||
**Correct (using @request context):**
|
||||
|
||||
```javascript
|
||||
// Check if user is authenticated
|
||||
createRule: '@request.auth.id != ""'
|
||||
|
||||
// Check ownership via auth record
|
||||
listRule: 'owner = @request.auth.id'
|
||||
viewRule: 'owner = @request.auth.id'
|
||||
updateRule: 'owner = @request.auth.id'
|
||||
deleteRule: 'owner = @request.auth.id'
|
||||
|
||||
// Access auth record fields
|
||||
// IMPORTANT: If using custom role fields, ensure update rules prevent
|
||||
// users from modifying their own role: @request.body.role:isset = false
|
||||
listRule: '@request.auth.role = "admin"'
|
||||
listRule: '@request.auth.verified = true'
|
||||
|
||||
// Validate request body on create/update
|
||||
createRule: '@request.auth.id != "" && @request.body.owner = @request.auth.id'
|
||||
|
||||
// Prevent changing certain fields
|
||||
updateRule: 'owner = @request.auth.id && @request.body.owner:isset = false'
|
||||
|
||||
// WARNING: Query parameters are user-controlled and should NOT be used
|
||||
// for authorization decisions. Use them only for optional filtering behavior
|
||||
// where the fallback is equally safe.
|
||||
// listRule: '@request.query.publicOnly = "true" || owner = @request.auth.id'
|
||||
// The above is UNSAFE - users can bypass ownership by adding ?publicOnly=true
|
||||
// Instead, use separate endpoints or server-side logic for public vs. private views.
|
||||
listRule: 'owner = @request.auth.id || public = true' // Use a record field, not query param
|
||||
|
||||
// Access nested auth relations
|
||||
listRule: 'team.members ?= @request.auth.id'
|
||||
```
|
||||
|
||||
**Available @request fields:**
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `@request.auth.id` | Authenticated user's ID (empty string if not authenticated) |
|
||||
| `@request.auth.*` | Any field from auth record (role, verified, email, etc.) |
|
||||
| `@request.body.*` | Request body fields (create/update only) |
|
||||
| `@request.query.*` | URL query parameters |
|
||||
| `@request.headers.*` | Request headers |
|
||||
| `@request.method` | HTTP method (GET, POST, etc.) |
|
||||
| `@request.context` | Request context: `default`, `oauth2`, `otp`, `password`, `realtime`, `protectedFile` |
|
||||
|
||||
**Body field modifiers:**
|
||||
|
||||
```javascript
|
||||
// Check if field is being set
|
||||
updateRule: '@request.body.status:isset = false' // Can't change status
|
||||
|
||||
// Check if field changed from current value
|
||||
updateRule: '@request.body.owner:changed = false' // Can't change owner
|
||||
|
||||
// Get length of array/string
|
||||
createRule: '@request.body.tags:length <= 5' // Max 5 tags
|
||||
```
|
||||
|
||||
Reference: [PocketBase API Rules](https://pocketbase.io/docs/api-rules-and-filters/#available-fields)
|
||||
Reference in New Issue
Block a user