AI Development Declaration
This module was written by AI agents. The module maintainer reviews and takes full responsibility for all the work done by AI.
Introduction
JSON:API Security Hardening module enhances the security of JSON:API–based applications by enforcing strict, defense-in-depth controls.
While Drupal core and contributed modules such as JSON:API Extras allow for granular configuration, additional security hardening is often beneficial. This module provides a "Secure by Default" global policy layer with enhanced privacy controls, query limits, and access restrictions.
Requirements
- Drupal 10.6+ or 11.2+
- JSON:API (Drupal core)
Features
1. Query Depth Limiting
Limits the depth of relationship chains in include queries.
- Policy: Enforces a global limit on the depth of the include parameter.
- Default: Limits requests to a depth of 2.
- Per-Resource Overrides: Specific resource types can be configured with custom depth limits (e.g., allow
menu_link_content--menu_link_content
a depth of 5 for menu hierarchies).
2. Collection Access Control
Restricts access to entity collection endpoints (e.g., /jsonapi/user/user).
- Policy: A global "Restrict Collection Access" switch.
- Effect:Blocks access to JSON:API collection endpoints with a 403 Forbidden response if the requesting user does not have access to the corresponding entity type's administrative collection route (e.g., /admin/people for users).
- Exceptions: Administrators can define specific resource types and roles that are allowed to bypass this restriction, regardless of administrative permissions. For example,
resource_type|role1,role2 (e.g., node--event|anonymous,authenticated). - Mapping: Explicitly map a resource type to a collection route to check access against.
- Reason: Some resources (like file--file) use a Drupal View for their collection endpoint instead of the standard JSON:API route. In these cases, the standard check fails because it can't automatically determine the administrative route.
- Format:
resource_type|route_name (e.g., file--file|view.files.page_1).
3. Strict Read-Only Mode
Enforces read-only policies at the API level.
- Policy: A global "Block Write Operations" switch with an Allowlist.
- Effect: Rejects POST, PATCH, and DELETE requests with a 405 Method Not Allowed.
- Exceptions: Administrators can define specific resources and methods that are allowed to accept write operations (e.g.,
contact_message--feedback|POST, PATCH).
4. UID 1 (Super User) Protection
Provides additional protection for the UID 1 (super user) account.
- Information Hiding: By default, access to UID 1's user data via JSON:API is completely blocked. Requests return a 404 Not Found response, hiding the UUID and all information of the account.
- Configuration: To allow access to UID 1 data, add the following to your settings.php:
$settings['jsonapi_security_allow_uid1_access'] = TRUE;
- Configuration: To allow access to UID 1 data, add the following to your settings.php:
- Login Blocking: By default, attempts to authenticate as UID 1 via JSON:API using HTTP Basic Authentication are blocked. Authentication will silently fail, returning a 401 Unauthorized response.
- Requirement: This feature only affects when the basic_auth module is enabled and login via the basic auth service.
- Configuration: To allow UID 1 access, add the following to your settings.php:
$settings['jsonapi_security_allow_uid1_login'] = TRUE;
5. Two-Factor Authentication (TFA) Integration (Sub-module)
Integrates Two-Factor Authentication (TFA) into JSON:API workflows.
jsonapi_security_tfa and requires the TFA module to be installed.
- Effect: Requires users to enable Two-Factor Authentication (TFA) before they can access or modify data via JSON:API.
- Installation: Enable separately via
drush en jsonapi_security_tfa. - Important: Once enabled, all users with existing sessions must re-login through the TFA flow to gain JSON:API access.
6. Security Logging
Logs security-relevant actions performed via JSON:API for audit purposes.
Installation
- Place the module in the
modules/customormodules/contribdirectory. - Enable the module via the Drupal admin UI or Drush:
drush en jsonapi_security - Configure the global policies at
/admin/config/services/jsonapi-hardening.
Configuration
All settings are managed from a single configuration screen.
1. Query Depth
- Limit Query Depth: [Checkbox]
- Max Depth: (Integer, default: 2)
- Depth Overrides: (Text Area) — Per-resource depth overrides in format
resource_type:depth(e.g.,menu_link_content--menu_link_content:5).
2. Collection Access Control
- Restrict Collection Access: [Checkbox] — Blocks access to collection endpoints unless the user has administrative listing permissions.
- Collection Route Mapping: (Text Area) — Map a resource type to a collection route. Format:
resource_type|route_name. Supports * wildcard. - Collection Restriction Exceptions: (Text Area) — Bypass rules in format
resource_type|role. Supports * wildcard.
3. Strict Read-Only
- Block Write Operations: [Checkbox] — Globally blocks POST/PATCH/DELETE.
- Write Exceptions: (Text Area) — One per line. Format:
resource_type|METHODS(e.g.,contact_message--feedback|POST, PATCH). Supports wildcards.
Extension Points
This module provides events for developers to extend or customize security policies:
| Event | Description |
|---|---|
JsonApiSecurityDepthCheckEvent |
Fired before depth validation. Allows custom logic to modify or bypass depth limits. |
JsonApiSecurityAnonymizeEvent |
Fired during response normalization. Allows custom logic to control field anonymization. |
JsonApiSecurityWriteCheckEvent |
Fired before write operation validation. Allows custom logic to permit or deny writes. |
Example usage:
use Drupal\jsonapi_security\Event\JsonApiSecurityDepthCheckEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class MySecuritySubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ JsonApiSecurityDepthCheckEvent::class => 'onDepthCheck', ]; } public function onDepthCheck(JsonApiSecurityDepthCheckEvent $event) { // Allow deeper includes for authenticated users. if ($this->currentUser->isAuthenticated()) { $event->setMaxDepth(5); } } }
Maintenance
This module follows Drupal security best practices. Security-related issues should be reported to the Drupal Security Team following by the disclosure policy.
Project information
- Project categories: Decoupled, Security
15 sites report using this module
- Created by mingsong on , updated
Stable releases for this project are covered by the security advisory policy.
There are currently no supported stable releases.
Releases
Development version: 1.0.x-dev updated 5 Feb 2026 at 11:16 UTC
