Skip to main content
Drupal is a registered trademark of Dries Buytaert
Release: Trash 3.0.33 Minor update available for module trash (3.0.33). EOL Warning: Drupal 11.0 has reached end of life and no longer receives security updates. EOL Warning: Drupal 10.3 has reached end of life and no longer receives security updates. Release: UI Patterns (SDC in Drupal UI) 2.0.20 Minor update available for module ui_patterns (2.0.20). Release: Trash 3.1.0-rc1 First release candidate for module trash (3.1.0-rc1). Release: Country 2.2.0 Minor update available for module country (2.2.0). Usage Milestone: jQuery UI Datepicker Module jquery_ui_datepicker crossed 1,000 active installs. Release: Scheduler Content Moderation Defaults 1.1.2 Minor update available for module scheduler_content_moderation_defaults (1.1.2). Release: Flags 2.1.0 Minor update available for module flags (2.1.0). Release: Login Disable 2.2.0 Minor update available for module login_disable (2.2.0).

This module allows you to restrict access to specific routes on your Drupal site based on the presence of certain HTTP headers. It's useful for creating private APIs or sections of your site that should only be accessible via specific applications or services.

Provides a Drupal route access check that validates incoming HTTP requests against configurable header profiles:

requirements:
  _routing_access_check_headers: 'xhr' # or 'iframe' or 'your_custom_header_check'

This is a developer module! - No UI, does nothing on its own. Typically useful if you have public (internal) API routes or embeds like iframes that should be protected against external calls, like widget_provider_api module or go-headless modules.

Overview

This module adds the _routing_access_check_headers route requirement. When a route uses this requirement, the access handler loads a routing access check headers profile plugin and calls checkAccess() on it.

The routing_access_check_headers module allows you to validate HTTP headers (like Origin or Referer) for internal API routes (e.g., XHR, JSON, or headless endpoints, e.g., from your frontend or iframe) that should never be accessed from external sources. Especially in cases where these endpoints need to be public and can't be secured by authentication. By enforcing header checks, you add a layer of protection against unauthorized cross-origin requests. Custom headers can also be validated for additional control.

While header validation makes it harder for external actors to query the endpoint, by blocking requests without the expected Origin or Referer, it is not a safe security measure on its own. Headers can be spoofed or omitted, so this should be combined with other protections like authentication, CSRF tokens (combination is possible, see below), or rate limiting. The module uses a plugin architecture, providing default plugins for xhr and iframe use cases, but you can also simply implement custom logic for specific needs.

Should you have further ideas how to add further hardening to this module, please create a feature request.

Profiles are defined as plugins and can validate:

  • custom request headers
  • the Origin header
  • the Referer header

Installation

Install as you would normally install a contributed Drupal module. For further information, see Installing Drupal Modules.

Route usage

Add the profile plugin ID to a route's requirements:

my_module.api_endpoint:
  path: '/api/example'
  defaults:
    _controller: '\Drupal\my_module\Controller\ExampleController::handle'
  methods: [GET]
  requirements:
    _routing_access_check_headers: 'my_profile_id'

The value (my_profile_id) must match the id of a profile plugin.

Combining with CSRF token

For routes that accept state-changing requests (for example POST), consider adding Drupal's CSRF access check alongside the header profile. See CSRF access checking.

requirements:
  _routing_access_check_headers: 'my_profile_id'
  _csrf_token: 'TRUE'

Built-in profiles

Profile ID Description xhr Allows programmatic requests (X-Requested-With: ''). iframe Allows requests loaded inside an iframe (@todo).

Example:

requirements:
  _routing_access_check_headers: 'xhr'

Creating a profile plugin

Profile plugins live in the Plugin/RoutingAccessCheckHeadersProfile namespace of any module that depends on routing_access_check_headers.

Example:

 'secret-value',
    'X-Client-Id' => '',
  ],
  validateOrigins: [
    'https://example.com',
  ],
  validateReferer: [
    'https://example.com/some-page',
  ],
)]
class MyProfile extends ProfilePluginBase {}

No additional code is required unless you want to customize the access logic.

Profile attribute options

Option Type Description id string Unique plugin ID. Referenced in routing requirements. customValidationHeaders array Required headers keyed by header name. Values are expected header values. Use an empty string to require the header without validating its value. validateHostOrigin bool Whether the server origin is included in Origin header checks. Defaults to FALSE. validateHostReferer bool Whether the server origin is included in Referer header checks. Defaults to FALSE. validateOrigins array Allowed Origin header prefixes. validateReferer array Allowed Referer header prefixes.

An empty customValidationHeaders array skips the custom header check. Origin and referer checks are skipped when no allowed values are configured for that header.

Access check logic

ProfilePluginBase evaluates checks in this order:

  1. checkAccess()
  2. checkHeaders()
  3. checkCustomHeaders()
  4. checkOrigin()
  5. checkReferer()

All checks must pass.

Custom headers

  • Skipped when no custom headers are configured.
  • Every configured header must be present on the request.
  • Configured values must match exactly.

Origin

  • Skipped when no allowed values are configured (validateOrigins is empty and validateHostOrigin is disabled).
  • When configured, requires the Origin header.
  • Allowed values are the configured validateOrigins and, when validateHostOrigin is enabled, the server origin.
  • The Origin value must start with one of the allowed values.

Referer

  • Skipped when no allowed values are configured (validateReferer is empty and validateHostReferer is disabled).
  • When configured, requires the Referer header.
  • Allowed values are the configured validateReferer and, when validateHostReferer is enabled, the server origin.
  • The Referer value must start with one of the allowed values.

Extending a profile

Extend ProfilePluginBase and override protected methods when you need custom logic:

  • checkAccess()
  • checkHeaders()
  • checkCustomHeaders()
  • checkOrigin()
  • checkReferer()
  • startsWithAllowedValue()
  • allowsSameOrigin()

Plugin definitions are read via:

  • getCustomHeaders()
  • getOriginsArray()
  • getReferer()
  • getHostOrigin()

Services

Both services use Symfony autowiring with service closures for lazy dependency resolution.

Service ID Description plugin . manager . routing_access_check_headers_profile Plugin manager for profile plugins. Uses service closures for cache . discovery and module_handler. routing_access_check_headers . access_check Route access check service tagged for _routing_access_check_headers. Uses a service closure for the profile plugin manager.

Alter hook

Profile plugin definitions can be altered with hook_routing_access_check_headers_profile_info_alter().

See routing_access_check_headers . api . php for hook documentation and example implementations.

Depends on

Dependencies of the latest stable release

No dependencies recorded for this project.

Required by

Tracked projects that depend on this one

No tracked projects depend on this one yet.

Activity

Tracked releases
3
Tracked since
Jul 2026
Latest release
1 month ago
Releases (12 mo)
3 ▲ from 0
Maintenance
Active

Release Timeline

Releases

Version Type Core Release date
1.0.0-alpha2 Pre-release 11 Jul 16, 2026
1.0.0-alpha1 Pre-release 11 Jul 16, 2026
1.x-dev Dev 11 Jul 14, 2026