# Common Rule Patterns — Firebase

Source: https://www.skillbyai.com/en/firebase/ru-patterns

> Owners, roles and validation.

## Functions, claims and field checks

Reusable **functions** keep rules readable. **Owner-only** access compares the path wildcard or a stored field with `request.auth.uid`. **Roles** come from custom claims (`request.auth.token.admin == true`) or from a document read with `get()` / `exists()`, which count as extra reads and are limited per request (check the docs). **Validation** checks types and shapes: `request.resource.data.keys().hasOnly([...])` blocks unknown fields, `diff(resource.data).affectedKeys().hasOnly([...])` limits which fields an update may change, and comparisons such as `request.time == request.resource.data.createdAt` force server timestamps. Validation in rules complements, not replaces, validation in your UI.

## Owner, admin and validated writes

Firestore Security Rules.

```javascript
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    function signedIn() { return request.auth != null; }
    function isOwner(uid) { return signedIn() && request.auth.uid == uid; }
    function isAdmin() { return signedIn() && request.auth.token.admin == true; }

    match /profiles/{uid} {
      allow read: if signedIn();
      allow create: if isOwner(uid)
        && request.resource.data.keys().hasOnly(['displayName', 'bio', 'createdAt'])
        && request.resource.data.displayName is string
        && request.resource.data.displayName.size() <= 50
        && request.resource.data.createdAt == request.time;
      allow update: if isOwner(uid)
        && request.resource.data.diff(resource.data).affectedKeys()
             .hasOnly(['displayName', 'bio']);
      allow delete: if isAdmin();
    }

    match /orgs/{orgId}/projects/{projectId} {
      allow read, write: if signedIn()
        && exists(/databases/$(database)/documents/orgs/$(orgId)/members/$(request.auth.uid));
    }
  }
}
```

## Protect role fields

If roles live in a user document, make sure users cannot update that field themselves, or a single write makes anyone an admin.

**Quiz:** Which expression stops an update from changing fields other than displayName and bio?

- [ ] allow update: if true
- [ ] resource.data.keys().size() == 2
- [ ] request.auth.token.admin == true
- [x] request.resource.data.diff(resource.data).affectedKeys().hasOnly(['displayName', 'bio'])

*Answer:* request.resource.data.diff(resource.data).affectedKeys().hasOnly(['displayName', 'bio']). diff().affectedKeys() lists changed fields.
