Skip to content

Security

Security controls, trust model, and ownership boundaries.

Contracts and schemas

Manifest contract (@favn/manifest-schema)

Validation at load time:

  • Required: id, semver version, displayName
  • featureType: domain or facet (default domain; application/module aliases accepted)
  • Required for domain: mount.pathPrefix, mount.domElementId, non-empty routes
  • Required for both: non-empty entrypoints.js
  • Server functions require module or endpoint plus non-empty exports
  • Endpoint must be absolute http/https without credentials
  • Runtime permissions, visibility metadata, and shared dep shapes validated
  • requirements.minHostVersion enforced against host version

Release index contract (@favn/manifest-tools/release-index)

  • Signed payload required
  • Fields: schemaVersion, featureId, sequence, activeVersion, versions[]
  • Sequence integer >= 1, versions semver and unique in descending order
  • activeVersion must exist in versions list
  • Each version requires manifestSha256

Signature contract (@favn/manifest-signature)

  • Algorithm: Ed25519
  • Signed payload: stable JSON stringify excluding the signature field
  • Trust keys sourced from env JSON, path, or single key
  • Dev keys allowed only when FEATURE_ALLOW_INSECURE_DEV_KEYS=1 and NODE_ENV is not production

Authentication model

RPC auth modes

Files: apps/host/src/rpc/middleware.ts, apps/host/src/auth/dfs-token-validation.ts, apps/host/src/auth/custom-auth-plugin.ts

ModeTriggerBehavior
dfs-oidc-verifiedDFS config + DFS_VALIDATE_ACCESS_TOKEN=1JWT verified against OIDC well-known/JWKS
static-tokenRPC_AUTH_TOKEN setBearer token match
trusted-clusterDIPS_TRUST_CLUSTER_AUTH=1Requires identity signal + optional ingress header assertion
noneFallbackNo RPC auth enforced

Custom plugin extension (HOST_AUTH_PLUGIN):

  • authorizeRpcRequest(context) can explicitly allow, deny, or skip
  • Can supply claims/roles and optionally skip role resolution

Route-level auth

For the catch-all feature route:

  • Resolves feature by longest mount.pathPrefix match
  • Only featureType: domain manifests participate in route matching
  • If feature.requirements.authRequired is true, authorizeRouteRequest() executes auth mode checks
  • Failure returns 401 or 503 with a public message

No per-feature role, toggle, or tenant authorization is enforced by the host at route render time.

API proxy identity enrichment

Flow:

  1. Optional custom plugin enrichment (enrichUpstreamHeaders)
  2. Strict mode can fail closed on enrichment errors

Identity claims passthrough

RPC auth middleware forwards role/group claims from generic token fields (role/roles) into ServerContext.userRoles. This is identity passthrough only; authorization semantics stay feature-owned and service-owned.

Visibility context

Host visibility context inputs:

  • Headers: x-feature-toggles, x-tenant-id
  • Signed cookie: host_context
  • Optional dev defaults

The host does not enforce role, toggle, or tenant visibility policies on routes or RPC. Visibility metadata is available for feature-owned logic and observability.

Host-enforced controls

  • Signed release indexes and manifests
  • Per-asset SRI verification before activation
  • Strict startup config validation with production safety checks
  • Route-level auth for authRequired features
  • RPC and API rate limits
  • RPC request body size limits and execution timeout
  • API proxy timeout and circuit breaker
  • Admin auth and CSRF mutation protection
  • Path traversal hardening for static/shared serving
  • Static and shared allowlists
  • CSP with nonce and constrained origins

Delegated to feature teams

  • Business authorization decisions inside server functions and services
  • Redaction and business data policy
  • Feature-specific role, toggle, and tenant policy semantics

Not enforced by host

  • Host does not globally enforce feature-specific visibility metadata semantics
  • No distributed or shared rate-limit state — limiter is in-memory per host instance