Drupal is a registered trademark of Dries Buytaert
Release: Drupal 11.4.5 Update released for Drupal core (11.4.5)! Release: Drupal 10.6.15 Update released for Drupal core (10.6.15)! Release: Superfish Dropdown Menu 8.x-1.15 Minor update available for module superfish (8.x-1.15). Release: Leaflet 10.4.10 Minor update available for module leaflet (10.4.10). Release: Raven: Sentry Integration 7.5.1 Minor update available for module raven (7.5.1). Release: htmLawed 8.x-3.8 Minor update available for module htmlawed (8.x-3.8). Release: Raven: Sentry Integration 7.5.0 Minor update available for module raven (7.5.0). Module Revived: Media Library Form API Element 2.1.5 Module media_library_form_element updated after 10 months of inactivity (2.1.5). Release: Acquia Content Optimization 2.1.0-alpha1 First alpha version released for module conductor (2.1.0-alpha1). Usage Milestone: Manage display Module manage_display crossed 1,000 active installs.

FileGate

4 sites No security coverage
View on drupal.org

File Gate restricts access to private files on your Drupal site, ensuring only authenticated or authorized users can download them. It works by generating short-lived, signed URLs that grant temporary access after passing a configured "gate," such as a login, token, or form submission, making it suitable for headless and decoupled sites. This module prevents anonymous users from accessing private files even if they have the direct link, with per-field configuration for easy setup and robust security.

File Gate gates the delivery of private files behind pluggable "gate methods" and streams them through its own signed endpoint. It is built for decoupled and traditional Drupal alike: a trusted back end mints a short-lived signed URL after running its own gate (a lead form, a login, a purchase, a step-up authentication) and any front end redeems it — the bytes are delivered only through File Gate, never through /system/files.

The problem it solves

Core's private file system grants an anonymous visitor download access to a private file whenever any published entity that references it is viewable. That is often too permissive for gated content, and it ties delivery to your Drupal site's own access model — awkward when the front end lives elsewhere. File Gate replaces that with an explicit, deny-by-default decision:

  • Deny by default. A hook_file_download() implementation returns a hard veto for any gated private file requested at /system/files, overriding core's permissive behaviour (unless the account holds an explicit bypass permission).
  • Self-hosted signed delivery. The file is streamed from GET /api/file-gate/download only after a gate method approves the request. The private path is never disclosed, and delivery does not depend on anonymous file access.
  • Front-end-agnostic. Mint returns a root-relative, host-agnostic path; your front end prepends its own public origin. The signing secret never reaches the browser.

Gate methods

A gate method answers one question: has this request passed the gate for this file? Five ship in the core module:

  • signed_url — a short-lived, HMAC-signed URL. Per-field TTL, an absolute availability window, and usage limits (a one-time link is max_uses = 1), all bound into the signature. Outstanding grants can be listed and revoked individually or in bulk (GET /api/file-gate/grants, POST /api/file-gate/grants/revoke-bulk, or by jti).
  • authenticated — deliver to a logged-in Drupal user, with an optional role allowlist.
  • token — a revocable per-grant token (its hash is stored and bound into the signature; revoke by deleting the hash, no secret rotation) and/or a pre-shared campaign-token allowlist for static links, with optional per-token TTL and max uses. Revoke is scoped to the mint credential's field allowlist.
  • referrer_lock — a signed URL that is additionally only redeemable from an allowed origin/referrer. Defence in depth, not authorization — the header is spoofable.
  • otp — a single-use one-time passcode e-mailed to a self-identified address. TTL-limited, attempt-locked, and hashed with the same authenticated secret material used for mint (named secrets and dual-key rotation included). Prefer POST /api/file-gate/otp/session so redeem uses an HttpOnly FG_OTP cookie instead of putting secrets in the query string.

Three more ship in optional submodules, so the core module stays dependency-light:

  • File Gate Form — a coupled form method: Drupal renders a lightweight email / lead-capture form and grants the download on submission. Spam-guarded (honeypot + per-IP rate limit); a LeadCapturedEvent lets the site persist leads into Contact, Webform, or a CRM without File Gate storing PII.
  • File Gate Commerce — a commerce method: deliver only to a buyer or licensee, re-checked live on every download so expiry and revocation take effect immediately. The bundled checker grants on a completed Drupal Commerce order matching a configured SKU via a SKU-scoped query (not a full order-history load); swap the entitlement-checker service for licences or an external API. Access gating, not DRM.
  • File Gate Assurance — an assurance method: gate delivery on a hardware-backed, phishing-resistant OIDC assurance level (PIV/CAC — HSPD-12 / FIPS 201 — or FIDO2/WebAuthn) proven at any standards-compliant IdP. Provider-agnostic (OIDC discovery + JWKS), with opt-in DPoP (RFC 9449), edge-mTLS for PIV/CAC behind a trusted proxy, and optional RFC 7662 introspection. For browser downloads, a short-lived session bridge cookie lets the same plain signed URL work after step-up (no second hop). On same-origin Drupal SSO, the bridge can use the site's openid_connect session access token when present. Field-configured authorize URLs can append IdP acr_values for step-up without open redirects. Native WebAuthn RP mode and a user enrollment UI are available when you do not use an IdP as the sole relying party. This is federation (NIST SP 800-63C, an asserted level), not File Gate acting as a full-site AAL3 verifier. Requires firebase/php-jwt; native WebAuthn additionally requires web-auth/webauthn-lib.

How it works

A back end calls POST /api/file-gate/mint (authenticated with a shared secret, constant-time, rate-limited) and receives a signed path. The browser redeems it at GET /api/file-gate/download. Minted token grants and signed-url jtis can be listed or invalidated at GET /api/file-gate/grants, POST /api/file-gate/revoke, and bulk revoke; one-time passcodes are issued at POST /api/file-gate/otp (prefer /api/file-gate/otp/session for cookie-based redeem). Every endpoint fails closed when no signing secret is configured.

Mint can require an acting account (global or per-field), pin a multi-field file to one storage key, verify an OIDC token at mint time (assurance A2), and re-check host-entity view rights for identity-aware grants. Named mint credentials are scoped to field allowlists so one front end cannot mint the whole corpus. Gating is a third-party setting on the file field storage — a toggle plus a gate-method picker that forces and locks the private file system.

Security model

  • Deny by default; every gate method must fail closed. The signing core is target-agnostic HMAC-SHA256 with constant-time comparison and an injective claim encoding.
  • Secrets are injected from the environment, not committed to config. Named secrets ($settings['file_gate.secrets']) can be limited to field scopes; minted URLs carry k=<id>, and scope is re-checked at redemption. Dual-key rotation keeps outstanding grants valid during cutover (previous_secrets / previous_download_secrets).
  • Step-up login for assurance uses only the field's configured absolute step_up_login_url — query overrides are ignored (open-redirect defence).
  • Download denial flood limits bound abuse on the redeem endpoint.
  • Optional soft integration with audit_chain for a durable, hash-chained security trail (mint, download, deny, revoke, OTP).
  • The admin settings page surfaces mint, delivery, and denial counts from the file_gate log channel when Database Logging is enabled.
  • File Gate is access gating, not DRM: it controls who receives the bytes, not what they do with them afterwards.
  • The Assurance module is federation (an asserted level), not an AAL3 verifier; a plain signed URL is a bearer capability unless DPoP-bound or bridge-bound. Trade-offs are documented in the submodule README and design note.

Requirements

Drupal ^11.4 || ^12. Core File only — Media is optional (gating works for any private file field, whether or not the file is wrapped in a media entity). The Assurance submodule additionally requires firebase/php-jwt (^6.10 || ^7.0); native WebAuthn mode also needs web-auth/webauthn-lib (^5). Both are suggested dependencies.

Documentation

The repository ships a full README.md, API reference (docs/API.md), architecture decisions (docs/ADR.md), assurance redeem / bridge notes (docs/assurance-redeem.md), secret rotation runbook, optional audit trail, E2E checklist, program plan, and the design note for PIV/CAC and WebAuthn. Please use the issue queue for bugs and feature requests.

Maintainers

Maintained by Jeremy Michael Cerda, sponsored by Wilkes & Liberty, LLC.

Activity

Tracked releases
16
Tracked since
Jul 2026
Latest release
4 days ago
Releases (12 mo)
16 ▲ from 0
Maintenance
Active

Release Timeline

Releases

Version Type Release date
1.6.1 Stable Aug 3, 2026
1.6.0 Stable Aug 3, 2026
1.5.2 Stable Aug 2, 2026
1.5.1 Stable Aug 2, 2026
1.5.0 Stable Jul 31, 2026
1.4.0 Stable Jul 31, 2026
1.3.0 Stable Jul 31, 2026
1.2.0 Stable Jul 31, 2026
1.1.0 Stable Jul 31, 2026
1.0.2 Stable Jul 30, 2026
1.0.1 Stable Jul 30, 2026
1.0.0 Stable Jul 24, 2026
1.x-dev Dev Jul 23, 2026
1.0.0-rc1 Pre-release Jul 14, 2026
1.0.0-beta1 Pre-release Jul 13, 2026
1.0.x-dev Dev Jul 13, 2026