Host Config & Security

Configure the permission model, action gating, plugin security, and content restrictions for the MP4E player.

Overview

MP4E uses a three-tier permission model that follows an intersection pattern: each layer can only restrict, never expand, what the previous layer allows. This ensures that no single party (creator, host, or viewer) can override the restrictions of another.

TierSourceControls
1. Creator Restrictionsmetadata.settings.restrictionsAuthor-declared limits embedded in the .mp4e file (e.g., sequential playback, blocked actions). Enforced by the engine even without host config.
2. Host Configconfig React propSandbox actions, disable overlays/layers/plugins/rules, gate actions for approval, plugin security rules.
3. Viewer PreferencessetViewerPreferences() at runtimePrivacy (doNotTrack, doNotShareIdentity, limitStorage) and accessibility (reducedMotion, highContrast). The viewer always has final say.
Three-tier permission model
// Three-tier permission model
// Each layer can only RESTRICT, never expand permissions.

// Tier 1: Creator restrictions (embedded in the .mp4e file)
metadata.settings.restrictions = {
  sequential: true,       // No seeking forward
  actions: { download: false }
};

// Tier 2: Host config (React prop)
<MP4EPlayer
  config={{
    sandbox: { actions: { openUrl: false } },
    gated: ['navigate'],
    disabled: { layers: ['debug-layer'] }
  }}
/>

// Tier 3: Viewer preferences (runtime, from player menu)
engine.setViewerPreferences({
  doNotTrack: true,
  reducedMotion: true
});
Intersection Model
If the creator blocks download and the host blocks openUrl, then both are blocked at runtime. Neither party can re-enable what the other has restricted.

MP4EConfig Reference

The config prop accepts an MP4EConfig object. It is passed to the WASM engine via setConfig() after setMetadata().

Sandbox

Block specific action types globally. Actions not listed are allowed by default.

PropTypeDefaultDescription
sandbox.actionsRecord<string, boolean>-Block or allow specific action types. Keys are action type strings (e.g. "openUrl", "navigate"). Values: true = allowed, false = blocked. Any action type not listed is allowed by default (default-open model).

Disabled Content

Suppress specific creator content by ID. Disabled items are silently removed from the engine's working set.

PropTypeDefaultDescription
disabled.overlaysstring[]-Array of overlay IDs to suppress. Matching overlays will not render.
disabled.pluginsstring[]-Array of plugin IDs to suppress. Matching plugins will not load or render.
disabled.layersstring[]-Array of layer IDs to suppress. All overlays within matching layers are hidden.
disabled.rulesstring[]-Array of rule IDs to suppress. Matching rules will not be evaluated or executed.
disabled.actionTypesstring[]-Array of action type strings to suppress globally. Any action of a matching type will be silently dropped.

Action Gating

Require host approval before executing certain action types. The engine pauses the action and invokes the onActionGate callback.

PropTypeDefaultDescription
gatedstring[]-Action types that require host approval before execution. When an action of a listed type fires, the engine pauses it and invokes the onActionGate callback. The host must call resolve(true) to allow or resolve(false) to deny.
gateTimeoutMsnumber5000How long (in milliseconds) the engine waits for the host to call resolve() on a gated action before applying the timeout policy.
gateTimeoutPolicy'allow' | 'deny''deny'What happens when the gate timeout expires without a resolve() call. "allow" lets the action proceed; "deny" silently drops it.

Plugin Security

Control network access, sandbox level, and signer requirements per plugin or group of plugins using wildcard patterns.

PropTypeDefaultDescription
pluginSecurityRecord<string, PluginSecurityRule>-Plugin security rules keyed by wildcard pattern. Patterns match plugin namespace:identifier format. Controls network access, sandbox level, and signer requirements per plugin or group of plugins. If set but no "*" key is provided, the implicit default is "none" (block all).
networkGateTimeoutMsnumber5000How long (in milliseconds) to wait for the host to resolve a network gate request before applying the timeout policy.
networkGateTimeoutPolicy'allow' | 'deny''deny'What happens when the network gate timeout expires. "allow" permits the request; "deny" blocks it.

Trust & Signing

Shortcuts for self-hosted deployments and plugin signature verification.

PropTypeDefaultDescription
trustContentbooleanfalseTrust all plugin content unconditionally. When true, every plugin receives the "trusted" sandbox level (allow-same-origin) regardless of other pluginSecurity rules. Use only for self-hosted deployments where you control all content.
trustedSignersRecord<string, string | true>-Trusted signers for plugin signature verification. Keys are signer names, values are base64-encoded Ed25519 public keys. The special value true for the key "mp4e" uses the built-in MP4E public key.

Action Gating

Action gating lets the host intercept specific action types before they execute. This is useful for confirming navigation, preventing unwanted URL opens, or logging action execution. The flow is:

  1. A rule or plugin triggers a gated action (e.g., openUrl)
  2. The engine pauses execution and invokes onActionGate(action, resolve)
  3. The host inspects the action and calls resolve(true) to allow or resolve(false) to deny
  4. If the host does not respond within gateTimeoutMs, the gateTimeoutPolicy applies
Action gating example
import { MP4EPlayer } from '@mp4e/react';
import '@mp4e/react/styles.css';

function SecurePlayer() {
  return (
    <MP4EPlayer
      src="/video.mp4"
      config={{
        gated: ['openUrl', 'navigate'],
        gateTimeoutMs: 10000,
        gateTimeoutPolicy: 'deny',
      }}
      onActionGate={(action, resolve) => {
        if (action.type === 'openUrl') {
          // Show a confirmation dialog before opening external URLs
          const approved = window.confirm(
            `This video wants to open: ${action.params.url}\nAllow?`
          );
          resolve(approved);
        } else if (action.type === 'navigate') {
          // Always allow in-app navigation
          resolve(true);
        } else {
          // Deny unknown gated actions
          resolve(false);
        }
      }}
    />
  );
}
Timeout Behavior
If the host never calls resolve(), the action is automatically denied (or allowed) after gateTimeoutMs based on the gateTimeoutPolicy. The default policy is "deny" (fail-closed).

Network Gating

When a plugin uses mp4e.fetch() to request a domain not in its allowed list, the onNetworkGate callback fires. This gives the host final say over which external requests plugins can make.

Network gating example
<MP4EPlayer
  src="/video.mp4"
  config={{
    networkGateTimeoutMs: 3000,
    networkGateTimeoutPolicy: 'deny',
  }}
  onNetworkGate={(request, resolve) => {
    // Only allow requests to your own domains
    const allowed = ['api.mysite.com', 'cdn.mysite.com'];
    const url = new URL(request.url);

    console.log(
      `Plugin ${request.pluginId} requesting ${request.method} ${request.url}`
    );

    resolve(allowed.includes(url.hostname));
  }}
/>

The callback receives the requesting plugin's ID, the full URL, and the HTTP method. Call resolve(true) to allow or resolve(false) to block the request. If the host does not respond within networkGateTimeoutMs, the networkGateTimeoutPolicy applies.

Plugin Security Rules

The pluginSecurity config field maps wildcard patterns to security rules. Patterns are matched against the namespace:identifier of each plugin.

PatternMatchesExample
'*'All plugins (global default)Baseline security for every plugin
'mp4e:*'All plugins in the mp4e namespaceOfficial MP4E plugins
'stripe:checkout'Exact plugin matchSpecific plugin elevated access
'!badguy:*'Deny rule (overrides positive matches at equal or lower specificity)Block an entire namespace
Implicit Default
If pluginSecurity is set but does not include a '*' key, the implicit default is "none" (all plugins blocked). Always include a '*' entry as your baseline.

PluginSecurityRule Type

PluginSecurityRule
interface PluginSecurityRule {
  /**
   * Network access policy:
   * - 'none': Block all network access
   * - 'manifest': Allow only domains declared in plugin manifest
   * - 'any': Unrestricted (dangerous, explicit opt-in only)
   * - string[]: Explicit domain allowlist (replaces manifest)
   */
  network?: 'none' | 'manifest' | 'any' | string[];

  /**
   * Sandbox level controlling iframe capabilities:
   * - 'contained': allow-scripts, allow-forms only (NO same-origin)
   * - 'connected': same + mp4e.fetch() + bridge storage
   * - 'trusted': + allow-same-origin (full host page access)
   */
  sandbox?: 'contained' | 'connected' | 'trusted';

  /** Required signer name -- plugin must be signed by this signer to render */
  signer?: string;
}

Full Example

Plugin security configuration
<MP4EPlayer
  src="/video.mp4"
  config={{
    pluginSecurity: {
      // Global default: contained sandbox, no network
      '*': {
        sandbox: 'contained',
        network: 'none',
      },

      // Official MP4E plugins: connected sandbox, manifest-declared domains
      'mp4e:*': {
        sandbox: 'connected',
        network: 'manifest',
        signer: 'mp4e',
      },

      // Stripe plugins: connected sandbox, explicit domain allowlist
      'stripe:*': {
        sandbox: 'connected',
        network: ['js.stripe.com', 'api.stripe.com'],
      },

      // Specific trusted plugin: full access
      'stripe:checkout': {
        sandbox: 'trusted',
        network: 'any',
      },

      // Block a known-bad namespace entirely
      '!badguy:*': {
        sandbox: 'contained',
        network: 'none',
      },
    },
  }}
/>

Content Restrictions

Content restrictions are creator-declared and embedded in metadata.settings.restrictions. They are the first tier of the permission model and are enforced by the engine even when no host config is provided. Think of them like SCORM sequencing rules.

MP4ERestrictions

PropTypeDefaultDescription
actionsRecord<string, boolean>-Action types the creator wants blocked. Same shape as config.sandbox.actions. Blocked actions are silently dropped by the engine.
sequentialbooleanfalseForce linear playback. When true, the viewer cannot seek forward past the furthest-watched point. Similar to SCORM's forwardOnly mode.
Restrictions in metadata
// Creator embeds restrictions in the video metadata
// These are enforced by the engine regardless of host config

{
  "settings": {
    "restrictions": {
      "sequential": true,
      "actions": {
        "download": false,
        "openUrl": false
      }
    }
  }
}
Sequential Playback
When sequential is enabled, the engine tracks the furthest-watched point and prevents seeking beyond it. This is commonly used for e-learning and compliance training videos where linear completion is required.

Security Violations

The onSecurityViolation callback fires when a plugin attempts a blocked network request (CSP violation). Use it for monitoring and alerting.

Security violation handler
<MP4EPlayer
  src="/video.mp4"
  onSecurityViolation={(violation) => {
    console.error(
      `Security violation by plugin ${violation.pluginId}:\n` +
      `  Blocked URI: ${violation.blockedURI}\n` +
      `  Violated directive: ${violation.violatedDirective}`
    );

    // Report to your monitoring service
    analytics.track('security_violation', {
      pluginId: violation.pluginId,
      blockedURI: violation.blockedURI,
      directive: violation.violatedDirective,
    });
  }}
/>
FieldTypeDescription
pluginIdstringThe ID of the plugin that triggered the violation.
blockedURIstringThe URI that was blocked by the Content Security Policy.
violatedDirectivestringThe CSP directive that was violated (e.g., "connect-src", "script-src").

Interactive Tool

Host Config Generator
The MP4E Studio includes an interactive Host Config Generator that lets you visually build your MP4EConfig object. Select action types to sandbox, choose plugins to disable, configure gating policies, and set up plugin security rules -- then copy the generated config directly into your code.

Full Production Example

Putting it all together -- a production-ready player with sandbox rules, action gating, plugin security, and violation monitoring:

Production player with full config
import { MP4EPlayer } from '@mp4e/react';
import '@mp4e/react/styles.css';

function ProductionPlayer({ videoUrl }: { videoUrl: string }) {
  return (
    <MP4EPlayer
      src={videoUrl}
      config={{
        // Block dangerous actions entirely
        sandbox: {
          actions: {
            download: false,
            openUrl: false,
          },
        },

        // Require approval for navigation
        gated: ['navigate', 'goToScene'],
        gateTimeoutMs: 8000,
        gateTimeoutPolicy: 'deny',

        // Disable specific creator content
        disabled: {
          layers: ['debug-layer'],
          actionTypes: ['console'],
        },

        // Plugin security per namespace
        pluginSecurity: {
          '*': { sandbox: 'contained', network: 'none' },
          'mp4e:*': { sandbox: 'connected', network: 'manifest' },
          'stripe:checkout': { sandbox: 'trusted', network: 'any' },
        },

        // Trust official MP4E signatures
        trustedSigners: { mp4e: true },
      }}

      // Gate callbacks
      onActionGate={(action, resolve) => {
        resolve(window.confirm(`Allow action: ${action.type}?`));
      }}
      onNetworkGate={(req, resolve) => {
        const trusted = ['api.mysite.com', 'cdn.mysite.com'];
        resolve(trusted.includes(new URL(req.url).hostname));
      }}
      onSecurityViolation={(v) => {
        console.error('Security violation:', v);
      }}
    />
  );
}