How to mask sensitive fields dynamically
Use Zchema to automatically prune fields from API responses, sanitize inputs, and mask OpenAPI schemas.
Instead of maintaining separate Pydantic models for public, user, and admin views (e.g., TaskPublic, TaskAdmin), ZCore provides dynamic, role-aware projection via Zchema.
1. Bind Schema to a Domain
Inherit from Zchema and set the __model__ class attribute to your domain identifier:
# schemas.py
import uuid
from zcore import Zchema
from pydantic import ConfigDict
class TaskResponse(Zchema):
__model__ = "tasks" # Binds this schema to the 'tasks' domain
id: uuid.UUID
title: str
salary: float # Sensitive field!
model_config = ConfigDict(from_attributes=True)2. Guest-Level Masking with __private__
If certain fields must never be exposed to unauthenticated public visitors (guests), declare them directly in the __private__ class variable:
# schemas.py
import uuid
from zcore import Zchema
from pydantic import ConfigDict
class TaskResponse(Zchema):
__model__ = "tasks"
__private__ = {"internal_notes", "cost_price"} # Stripped for unauthenticated visitors
id: uuid.UUID
title: str
salary: float
cost_price: float = 0.0
internal_notes: str | None = None
model_config = ConfigDict(from_attributes=True)When an unauthenticated request hits the endpoint (ctx.user_id is None), ZCore automatically purges these fields from response serialization, input validation, and dynamic OpenAPI schema generation without requiring active context lookups.
3. Set Restrictions in Context
During your authentication flow (or inside BaseAuth), load the active user's restricted paths into ctx.restricted_fields:
from zcore import ctx
# Mask 'salary' specifically on view/GET requests for the 'tasks' domain
ctx.restricted_fields = ["tasks.view.salary"]4. Automatic Response Pruning
When your endpoint returns a TaskResponse model or dictionary, Zchema intercepts serialization and removes restricted keys:
// Normal Output (Admin)
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"title": "Build Architecture",
"salary": 120000.0
}
// Filtered Output (Restricted User)
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"title": "Build Architecture"
// 'salary' is pruned automatically!
}Restriction Path Syntax
| Pattern | Example | Effect |
|---|---|---|
<domain>.<action>.<field> | tasks.view.salary | Prunes salary only on view (GET) actions. |
<domain>.<field> | tasks.salary | Globally prunes salary across all actions (create, update, view). |
<domain>.<action>.<nested.path> | tasks.view.author.email | Recursively traverses dicts/lists to prune email. |
<domain>.<action> | tasks.view | Masks the entire model representation (*). |
Bidirectional Protection & CDN Safety:
- Input Sanitization (Mass Assignment):
Zchemaalso filters incoming input payloads, silently dropping restricted fields before they reach your database services. - Cache Protection (
VaryHeader): When fields are pruned, ZCore automatically appendsVary: Authorization, Cookieto HTTP response headers to prevent intermediate proxies or CDN caches from serving masked data to authorized users.