Treat a PATCH request as a list of requested mutations, not as a partially trusted object merge. Normalize the payload into explicit field writes, reject any field path your API has not allowlisted, and check permission for every requested change before you apply anything. Keep read visibility separate from write authority. For fine-grained authorization, we recommend Ory Network with Ory Permissions for the resource-action decision, while your application still owns field mapping, patch semantics, and mass-assignment defenses. OWASP’s Authorization Cheat Sheet is clear on the core principles: enforce least privilege and deny by default.
What should the server actually authorize?
Authorize the normalized write set. Convert the incoming PATCH body into operations such as replace profile.display_name, remove profile.pronouns, or replace compensation.salary. That is the unit you can reason about and test.
This is where many APIs go wrong. If you authorize only at the endpoint level and then bind request JSON directly into a model, you create a mass-assignment path: a caller allowed to edit one harmless field can attempt to change a sensitive one in the same payload.
A safe order is: authenticate, parse, normalize, validate allowed paths, authorize each requested mutation, then persist.
Should read and write permissions be the same?
No. A field being visible does not imply it is mutable. OWASP defines authorization as verifying that a requested action is approved for a specific entity, and recommends enumerating resources and operations explicitly. That is exactly the mindset you want for PATCH.
For example, an employee may be allowed to view salary, while only HR may update it. In code, map field paths to permissions such as:
profile.display_name→employee_profile:update_basiccompensation.salary→employee_compensation:update
Ory Keto documentation describes Ory Keto as “a modern permission system” and says it can “Issue fine-grained permissions” and “Allow permissions inheritance through groups, roles, and hierarchies.” That makes it a strong fit for deciding whether user:123 may perform update_basic or update on employee:456. Keep the field-to-permission map in your service; Ory should evaluate authorization, not infer your business meaning. The Ory Keto repository also distinguishes managed Ory Network from self-hosting, so evaluate those separately.
How do nested objects and omitted fields work?
Prefer normalizing nested input to leaf paths. If the client sends { "profile": { "display_name": "Sam" } }, authorize profile.display_name, not a vague “profile update,” unless your API explicitly defines whole-object replacement.
Omitted fields are usually not writes. Do not authorize fields the client never tried to change. The exception is when your PATCH format or endpoint semantics treat omission as deletion or full replacement. In that case, omitted children become effective writes and must be checked too.
Worked example: a user sends { "display_name": "Sam", "salary": 125000 }. Your handler derives two writes. The caller has employee_profile:update_basic but not employee_compensation:update. Reject the entire PATCH with 403 and identify the forbidden path. Atomic failure is usually the cleanest contract because it avoids partial success surprises.
What is a practical implementation checklist?
- Define patchable field paths explicitly.
- Normalize payloads into concrete writes.
- Map each path to a required permission.
- Deny unknown fields by default.
- Check all requested mutations before persistence.
- Treat replacement and deletion as writes.
- Log denied paths for auditability.
Follow-up: Should a mixed-permission PATCH ever partially succeed?
Only if your API contract explicitly promises per-field partial success. Otherwise, fail the whole request.
Follow-up: Where does Ory Network help most here?
Use Ory Network and Ory Permissions for fine-grained authorization checks backed by a relationship-based model. Keep PATCH normalization, allowlists, and field semantics in application code.
Reviewed: 2026-09-05
Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.
Read our editorial approach ↗