Appearance
Security
Security controls, trust model, and ownership boundaries.
Contracts and schemas
Manifest contract (@favn/manifest-schema)
Validation at load time:
- Required:
id, semverversion,displayName featureType:domainorfacet(defaultdomain;application/modulealiases accepted)- Required for
domain:mount.pathPrefix,mount.domElementId, non-emptyroutes - Required for both: non-empty
entrypoints.js - Server functions require
moduleorendpointplus non-emptyexports - Endpoint must be absolute
http/httpswithout credentials - Runtime permissions, visibility metadata, and shared dep shapes validated
requirements.minHostVersionenforced 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
activeVersionmust exist in versions list- Each version requires
manifestSha256
Signature contract (@favn/manifest-signature)
- Algorithm: Ed25519
- Signed payload: stable JSON stringify excluding the
signaturefield - Trust keys sourced from env JSON, path, or single key
- Dev keys allowed only when
FEATURE_ALLOW_INSECURE_DEV_KEYS=1andNODE_ENVis 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
| Mode | Trigger | Behavior |
|---|---|---|
dfs-oidc-verified | DFS config + DFS_VALIDATE_ACCESS_TOKEN=1 | JWT verified against OIDC well-known/JWKS |
static-token | RPC_AUTH_TOKEN set | Bearer token match |
trusted-cluster | DIPS_TRUST_CLUSTER_AUTH=1 | Requires identity signal + optional ingress header assertion |
none | Fallback | No 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.pathPrefixmatch - Only
featureType: domainmanifests participate in route matching - If
feature.requirements.authRequiredis true,authorizeRouteRequest()executes auth mode checks - Failure returns
401or503with 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:
- Optional custom plugin enrichment (
enrichUpstreamHeaders) - 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
authRequiredfeatures - 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