Если REST API в WordPress отвечает 403 Forbidden только тогда, когда запрос идет с заголовком Authorization, проблема обычно не в самом WordPress, а в связке серверного прокси, WAF, плагинов безопасности или конфигурации PHP-FPM/Apache. Это типичный сценарий для интеграций с внешними сервисами, мобильными приложениями, headless-фронтендом и кастомными эндпоинтами.
Ниже — практический разбор: как локализовать источник блокировки, что проверить в конфигурации, какие правки действительно помогают и как убедиться, что после изменений API работает стабильно.
Как выглядит проблема на практике
Обычно симптомы такие:
/wp-json/открывается в браузере, но POST/GET-запросы с токеном получают 403;- без заголовка
Authorizationтот же эндпоинт отвечает нормально; - в логах сервера виден
403, но WordPress-ошибка не формируется; - в админке все работает, а внешняя интеграция ломается;
- после установки плагина безопасности или включения CDN проблема появляется внезапно.
Важно не путать этот кейс с 401 Unauthorized. 401 обычно означает, что аутентификация не прошла. 403 чаще говорит о том, что запрос отрезали раньше, чем WordPress успел его обработать.
Диагностика: где именно теряется Authorization
Начинать стоит не с правки кода, а с проверки цепочки запроса. В WordPress сам REST API не блокирует Authorization как класс. Чаще всего заголовок теряется на уровне веб-сервера или прокси.
1. Проверьте, доходит ли заголовок до PHP
Самый быстрый способ — временно вывести заголовки в mu-plugin или в тестовый плагин. Для продакшена так не оставляют, но для диагностики это полезно.
<?php
/**
* Plugin Name: Header Debug
*/
add_action('init', function () {
if (!defined('REST_REQUEST') || !REST_REQUEST) {
return;
}
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
error_log('HTTP_AUTHORIZATION: ' . $_SERVER['HTTP_AUTHORIZATION']);
} elseif (function_exists('getallheaders')) {
$headers = getallheaders();
if (!empty($headers['Authorization'])) {
error_log('Authorization: ' . $headers['Authorization']);
}
}
});Если в логах пусто, а клиент точно отправляет заголовок, значит он отрезается до WordPress.
2. Посмотрите ответ сервера без WordPress-слоя
Проверьте запрос через curl. Это помогает отделить проблему клиента от проблемы сервера.
curl -i https://example.com/wp-json/wp/v2/users/me \
-H 'Authorization: Bearer YOUR_TOKEN'Если в ответе сразу 403 и в access/error log нет следов обработки WordPress, ищите блокировку в Nginx, Apache, ModSecurity, Cloudflare или другом WAF.
3. Проверьте плагины безопасности и кеширования
Некоторые плагины безопасности фильтруют заголовки или режут REST-запросы по сигнатурам. Особенно это заметно, если включены:
- ограничение REST API для неавторизованных пользователей;
- защита от XML-RPC и «подозрительных» заголовков;
- скрытие
wp-jsonили жесткая фильтрация запросов к нему; - firewall-режим с блокировкой bearer-токенов.
Если после временной деактивации плагина проблема исчезает, это уже не гипотеза, а рабочая точка входа.
Что исправлять в первую очередь
Ниже — порядок, который обычно экономит время. Не меняйте все сразу: так сложнее понять, что именно помогло.
1. Передайте Authorization в PHP
На Nginx и некоторых конфигурациях PHP-FPM заголовок Authorization не попадает в $_SERVER автоматически. Для Nginx часто помогает явная передача заголовка в FastCGI.
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_AUTHORIZATION $http_authorization;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}Для Apache иногда нужен модуль mod_rewrite или корректная передача заголовков в связке с PHP-FPM. Если используется прокси, проверьте, не обнуляет ли он Authorization на уровне upstream.
2. Если стоит Cloudflare или другой WAF, проверьте правила
WAF может блокировать запросы с токенами, если они похожи на автоматизированный трафик. Ищите в логах события, связанные с:
- REST endpoint;
- заголовком
Authorization; - подозрительными user-agent;
- rate limiting для API-путей.
Иногда достаточно добавить исключение для /wp-json/* или конкретного маршрута, если он используется только вашим приложением.
3. Уберите конфликтующий фильтр в теме или плагине
Если в проекте есть кастомный код, проверьте фильтры, которые могут вмешиваться в REST:
<?php
add_filter('rest_authentication_errors', function ($result) {
if (!empty($result)) {
return $result;
}
// Нельзя бездумно возвращать WP_Error здесь — это ломает авторизацию.
return $result;
});Частая ошибка — разработчик добавляет жесткую проверку и случайно блокирует все запросы, кроме админских. Если есть свой фильтр rest_authentication_errors, временно отключите его и повторите запрос.
Сравнение подходов: сервер, плагин или код
| Подход | Когда подходит | Плюсы | Минусы |
|---|---|---|---|
| Правка Nginx/Apache | Заголовок теряется до PHP | Решает причину, а не симптом | Нужен доступ к конфигу сервера |
| Исключение в WAF/CDN | 403 идет от защиты | Быстро снимает блокировку | Нужно аккуратно не ослабить защиту целиком |
| Правка плагина/темы | Конфликт в кастомном коде | Точечное исправление | Требует ревизии кода и теста регрессий |
Пошаговое решение без лишнего риска
- Сделайте копию конфигурации сервера и списка активных плагинов.
- Проверьте, доходит ли
Authorizationдо PHP через логирование. - Если заголовок теряется, добавьте его передачу в Nginx или проверьте прокси.
- Если заголовок доходит, временно отключите плагины безопасности и кеша.
- Повторите запрос через
curlи через реальный клиент. - Если виноват кастомный код, найдите фильтры
rest_authentication_errorsи связанные проверки прав.
Для проверки после каждого шага используйте один и тот же запрос. Иначе легко получить ложный вывод: один клиент может отправлять заголовок иначе, чем другой.
Как проверить, что решение сработало
Проверка должна быть не только визуальной. Нужны минимум три сигнала:
curlвозвращает ожидаемый код ответа, а не403;- в логах PHP появляется
HTTP_AUTHORIZATIONили заголовок доступен в обработчике; - реальная интеграция, которая раньше падала, проходит аутентификацию и получает данные.
Если вы исправляли серверную конфигурацию, перезапустите PHP-FPM и веб-сервер, затем повторите тест. Если меняли плагин безопасности, проверьте не только один эндпоинт, а несколько маршрутов REST API, которые используются в проекте.
Частые ошибки и почему они ломают REST API
- Проверяют только браузер. Браузерный запрос может идти без нужного заголовка или сессии, поэтому проблема маскируется.
- Отключают все плагины навсегда. Это не диагностика, а потеря контроля. Нужен поэтапный тест.
- Добавляют исключение для всего
/wp-json/без необходимости. Так можно ослабить защиту шире, чем требуется. - Правят WordPress-код вместо сервера. Если заголовок не доходит до PHP, никакой фильтр в WordPress не поможет.
- Не учитывают CDN. Запрос может блокироваться на edge-уровне, а в серверных логах его вообще не будет.
Безопасность и производительность: что не стоит делать
Не отключайте REST API глобально только ради обхода ошибки. Это ломает интеграции, редактор, мобильные сценарии и может создать ложное ощущение безопасности. Лучше ограничить доступ точечно: по маршруту, по IP, по токену или по роли, если это действительно нужно проекту.
Если у вас много технических дублей, мусорных архивов и лишних точек входа в индексацию, имеет смысл отдельно навести порядок в SEO-слое и служебных страницах. Для таких задач иногда используют Clearfy Pro: он помогает убрать часть технического шума и дублирующих сущностей, но проблему 403 на REST API он сам по себе не решает.
Когда стоит смотреть в сторону кастомной аутентификации
Если внешний сервис работает нестабильно через cookie-auth или basic auth, лучше перейти на более предсказуемую схему: application passwords, OAuth-подобный шлюз или собственный токен-слой с жесткой проверкой маршрутов. Важно, чтобы способ аутентификации соответствовал вашему стеку и не зависел от случайных особенностей прокси.
Для проектов, где REST API — часть основного продукта, полезно документировать:
- какие эндпоинты доступны извне;
- какой тип авторизации используется;
- какие заголовки обязательны;
- какие правила WAF/CDN должны быть исключены;
- какие плагины могут влиять на маршрут.
Такой список экономит часы, когда 403 появляется после обновления сервера, плагина безопасности или CDN-правил.