Skip to main content

How to Configure Payload Encryption

Framework M supports four payload encryption modes. This guide explains how to enable and tune them.

Choose a Mode

ModeWhat is encryptedBest for
disabledNothingLocal development, CI, trusted internal services
selectiveRoutes you configure (auth routes by default)Standard SaaS deployments
metadataDocType fields flagged encrypted or piiGranular PII protection in Desk forms
strictAll mutating requests (POST, PUT, PATCH)Fintech, zero-trust enterprise

Global Configuration

Set the mode in pyproject.toml or your web_config.toml:

[tool.framework_m.security.payload_encryption]
mode = "selective"
jwks_uri = "/api/v1/security/jwks"

# Optional: extend the default selective routes
routes = [
"/api/v1/auth/login",
"/api/v1/auth/register",
"/api/v1/payments/charge",
]

When routes is omitted in selective mode, the framework defaults to all authentication endpoints:

  • /api/v1/auth/login
  • /api/v1/auth/register
  • /api/v1/auth/forgot-password
  • /api/v1/auth/reset-password
  • /api/v1/auth/otp
  • /api/v1/auth/magic-link

Flagging DocType Fields (metadata mode)

In metadata mode, Desk forms automatically encrypt fields marked in the DocType schema:

from pydantic import Field
from framework_m_core.domain.base_doctype import BaseDocType


class PatientRecord(BaseDocType):
name: str = Field(json_schema_extra={"pii": True})
email: str = Field(json_schema_extra={"pii": True, "encrypted": True})
ssn: str = Field(json_schema_extra={"encrypted": True})
diagnosis_code: str = Field()

The metadata router exposes these flags in GET /meta/PatientRecord. The Desk useFormController reads the schema and passes it to the data provider, which encrypts the payload when any flagged field is present.

caution

Use json_schema_extra flags on DocType models only. Litestar request/response DTOs (such as LoginRequest) cannot carry unknown json_schema_extra keys because Litestar's OpenAPI generator rejects them. Auth routes are protected by selective mode route configuration instead.

Behavior Matrix

Global Modeencrypted=Truepii=TrueResult
disabledIgnoredIgnoredCleartext JSON
selectiveEncrypted if route is in the listTreated as encrypted=True for listed routesRoute list wins
metadataAlways encryptedTreated as encrypted=TruePII fields encrypted automatically
strictAlways encrypted for mutationsAlways encrypted for mutationsAll POST/PUT/PATCH bodies encrypted

Verifying Encryption

  1. Start the application with mode = "selective".
  2. Open the browser DevTools Network tab.
  3. Submit a login form.
  4. The POST /api/v1/auth/login request should have:
    • Content-Type: application/jose
    • A JWE envelope body instead of cleartext JSON.

Disabling for Development

Use mode = "disabled" (the default) so Chrome DevTools and Postman show cleartext JSON:

[tool.framework_m.security.payload_encryption]
mode = "disabled"
warning

Never use disabled in production for sensitive endpoints.