Field-Level Access Control (FLAC)
Field-level security in SveltyCMS β what is enforced today (filter/search + API read filtering) and the schema-level utilities built for write guards.
On this page
SveltyCMS implements field-level security in two layers:
- Schema-based FLAC utilities (
src/utils/field-access.ts):canAccessField/enforceFieldAccessevaluate per-fieldpermissions(visibility,requiredAuth,readRoles,writeRoles) declared in the Collection Builder. FIELD_PERMISSIONSresponse filter (August 2026): a cached settings-level policy ({collection: {role: [readable fields]}}) applied to API read responses inhandle-token-resolution.
This page describes both, and is explicit about what is enforced in the request path today versus what is built but not yet wired.
π‘οΈ Enforcement Status (Truthful)
| Layer | Status | Where |
|---|---|---|
| Filter/search whitelist β non-readers cannot filter (or search) restricted fields | β Enforced | collection-filter-engine.ts uses canAccessField per field schema |
| API read responses β fields filtered per role policy | β Enforced | FIELD_PERMISSIONS setting applied in handle-token-resolution (admin / absent-policy fast-paths) |
UI configuration β per-field readRoles / writeRoles / visibility / requiredAuth |
β Enforced | Collection Builder β field β Permissions tab (modal-widget-form.svelte) |
Full read-stripping on fetch (enforceFieldAccess, nested + i18n key removal) |
β³ Utility ready, not wired | src/utils/field-access.ts; wiring is a roadmap item |
Write rejection β 403 + UNAUTHORIZED_ACCESS audit on guarded-field writes |
β³ Utility ready, not wired | enforceFieldAccess(operation: "write"); wiring is a roadmap item |
Parity status (as of 2026-08-10): the read side is production-shipped; the write-guard side of the schema-level FLAC utilities is implemented and unit-tested but not yet invoked by the mutation pipeline. This is tracked in the 2026 Roadmap under Field-level write guards.
ποΈ Architecture
handle-token-resolution] D --> E[Filter/search whitelist
canAccessField in collection-filter-engine] end subgraph Schema FLAC Utilities src/utils/field-access.ts F --> G[canAccessField per-field check] E --> G G --> H[enforceFieldAccess - read stripping] G --> I[enforceFieldAccess - write rejection 403 + audit] end H --> J[Sanitized JSON Response] I -- "not yet wired" --> K[Roadmap: mutation pipeline]
βοΈ Configuration
Per-field schema policy (Collection Builder)
FLAC is configured per-field in the Collection Builder under the Permissions tab.
// Technical Representation in Schema
{
db_fieldName: "internal_notes",
widget: widgets.Textarea,
permissions: {
visibility: "private",
requiredAuth: true,
readRoles: ["admin", "editor"],
writeRoles: ["admin"]
}
}
Settings-level response policy (FIELD_PERMISSIONS)
Admins may also define a collection β role β readable-fields map via System Settings. When present, it filters API read responses in handle-token-resolution:
{
"posts": {
"editor": ["title", "body", "status"],
"contributor": ["title"],
},
}
The memo is invalidated on settings save; admin and absent-policy requests skip the filter entirely (zero hot-path cost).
π‘οΈ Security Guarantees
1. Filter / Search Protection (enforced)
canAccessField is invoked by collection-filter-engine.ts before any query is built. Fields the callerβs role cannot read are excluded from where / whereBetween / search clauses β restricted fields cannot be used to probe data through filtering or full-text search.
2. Read Response Filtering (enforced)
API read responses are field-filtered against the FIELD_PERMISSIONS policy. Only readable fields reach the client; localized variants and nested paths are covered by the policy structure.
3. Physical Stripping + Strict Write Rejection (utility ready, wiring pending)
enforceFieldAccess (when wired) will:
- Read: delete restricted keys from the JSON object, including all localized variants (e.g.,
title_de,title_fr) and nested dot-notation paths. - Write: collect all violations, throw
AppError(403, "FORBIDDEN"), and emit anUNAUTHORIZED_ACCESSaudit event with the blocked fields, collection, and entry β before the transaction proceeds.
4. Fail-Closed Default
Both utilities fail closed: an empty readRoles / writeRoles array denies everyone except admin/system; hidden or private fields require explicit role membership; anonymous (public) callers are denied when requiredAuth is set.
π Performance Impact
- O(N) sanitization β a single pass over the field schema.
- Zero-cost fast-path β admin and
systemusers bypass FLAC entirely;FIELD_PERMISSIONSfast-paths skip the filter when no policy matches. - Memoized policy β the
FIELD_PERMISSIONSmap is cached and only invalidated on settings save.
π Related Documentation
- Security Overview
- Role-Based Access Control (RBAC)
- Collection Filtering Platform
- 2026 Roadmap β Field-level write guards