Если REST API WordPress отвечает 403 Forbidden только для запросов с авторизацией, а обычные публичные эндпоинты работают, проблема чаще всего не в самом WordPress. На практике виноваты Nginx, прокси, модуль PHP-FPM, плагин безопасности или правило, которое режет заголовок Authorization до того, как запрос доходит до wp-json.
Ниже — рабочий сценарий диагностики и исправления для типичного сайта на WordPress, где API используют для мобильного приложения, внешнего сервиса, headless-фронтенда или интеграции с админкой.
Как выглядит проблема и что именно ломается
Симптомы обычно похожи друг на друга:
/wp-json/открывается, но конкретный защищённый маршрут возвращает403;- запрос с токеном или Basic Auth проходит локально, но падает на продакшене;
- в логах WordPress нет нужной записи, потому что запрос блокируется раньше;
- после включения плагина безопасности или CDN ошибка появляется только для API.
Важно разделять две ситуации: WordPress действительно отклоняет запрос по правам доступа и сервер режет заголовок или сам запрос на уровне веб-сервера. Это разные причины и разные исправления.
Диагностика: где именно возникает 403
Начинать лучше не с правки кода, а с проверки цепочки запроса. Это экономит время и помогает не лечить не ту проблему.
1. Проверить, доходит ли заголовок Authorization до PHP
Самый простой тест — временно вывести заголовки в лог или в небольшой mu-plugin. Если Authorization пустой, WordPress не сможет обработать токен или Basic Auth корректно.
<?php
/**
* Plugin Name: Debug Authorization Header
*/
add_action('init', function () {
if (defined('WP_DEBUG') && WP_DEBUG && isset($_SERVER['REQUEST_URI']) && str_contains($_SERVER['REQUEST_URI'], '/wp-json/')) {
error_log('AUTH HEADER: ' . ($_SERVER['HTTP_AUTHORIZATION'] ?? 'EMPTY'));
}
});Если в лог попадает EMPTY, проблема почти наверняка на уровне Nginx, Apache, прокси или CDN.
2. Проверить ответ без плагинов безопасности
Если есть доступ к staging-копии, временно отключите плагины, которые фильтруют REST API, XML-RPC, заголовки или подозрительные запросы. Часто блокируют не весь API, а только методы POST, PUT или запросы с нестандартным User-Agent.
Для быстрой проверки удобно сделать запрос через curl:
curl -i https://example.com/wp-json/wp/v2/users/me \
-H 'Authorization: Basic base64loginpassword'Если на одном сервере запрос проходит, а на другом нет, сравнивайте не WordPress, а конфигурацию веб-сервера и промежуточных слоёв.
Почему Nginx часто режет Authorization header
В связке Nginx + PHP-FPM заголовок Authorization нередко не передаётся в PHP автоматически. Тогда WordPress видит запрос, но не видит данные авторизации. Для REST API это критично, если вы используете Basic Auth, Application Passwords или внешний шлюз, который полагается на этот заголовок.
Проверьте конфиг сайта в Nginx. В блоке location ~ \.php$ обычно нужен явный проброс:
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;
}На некоторых сборках вместо fastcgi_params используется fastcgi.conf. Смысл один: передать заголовок в PHP как переменную окружения.
Если перед вами Apache
Для Apache проблема встречается реже, но тоже бывает, особенно если сайт работает через CGI/FastCGI или за прокси. Тогда помогает правило в .htaccess или конфиге виртуального хоста:
RewriteEngine On
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]Если запрос идёт через балансировщик или CDN, проверьте, не удаляет ли он заголовок на своём уровне. В таком случае правка WordPress не поможет.
Пошаговое решение: что менять и в каком порядке
Ниже порядок, который обычно даёт быстрый результат без лишних откатов.
Шаг 1. Исправить передачу заголовка на сервере
Сначала внесите правку в Nginx или Apache и перезапустите сервис. После этого повторите тест с curl. Если Authorization появился в логах PHP, половина проблемы уже решена.
Шаг 2. Проверить правила безопасности
Если заголовок доходит, но 403 остаётся, смотрите плагины безопасности, WAF и правила модерации запросов. Типичные причины:
- блокировка REST API для неавторизованных пользователей;
- запрет методов
POSTиDELETEдля/wp-json/; - фильтрация по
Authorizationкак по “подозрительному” заголовку; - защита от brute force, которая ошибочно срабатывает на API.
Если используется плагин, который умеет отключать лишние REST-эндпоинты, проверьте, не выключен ли нужный маршрут. Удобнее сначала протестировать на чистой staging-копии, а потом переносить изменения на боевой сайт.
Шаг 3. Убедиться, что WordPress не режет доступ сам
Если вы пишете свой endpoint через register_rest_route(), проверьте callback permission_callback. Ошибка часто не в авторизации, а в том, что callback всегда возвращает false или ожидает роль, которой у пользователя нет.
add_action('rest_api_init', function () {
register_rest_route('myplugin/v1', '/profile', [
'methods' => 'GET',
'callback' => 'myplugin_get_profile',
'permission_callback' => function () {
return current_user_can('read');
},
]);
});
function myplugin_get_profile(WP_REST_Request $request) {
return rest_ensure_response([
'user_id' => get_current_user_id(),
'email' => wp_get_current_user()->user_email,
]);
}Если permission_callback слишком жёсткий, WordPress вернёт rest_forbidden, и это уже не серверная проблема.
Как проверить, что решение сработало
Проверка должна быть не одной, а минимум в трёх точках:
- запрос через
curlс нужным заголовком; - тот же запрос из внешнего клиента или Postman;
- проверка в логах PHP-FPM, Nginx и WordPress debug log, если он включён.
Полезно сравнить ответы до и после правки:
| Подход | Что проверяет | Ограничение |
|---|---|---|
| curl с Authorization | Доходит ли заголовок и отвечает ли маршрут | Не показывает поведение браузера |
| Postman / Insomnia | Реальный внешний клиент | Нужна ручная настройка |
| Логи Nginx/PHP | Где именно теряется запрос | Требует доступа к серверу |
Если после правки серверной конфигурации Authorization виден в PHP, а endpoint всё ещё отдаёт 403, значит проблема уже в правах пользователя, nonce, callback маршрута или плагине безопасности.
Частые ошибки и как их исправить
Забыли перезапустить PHP-FPM или Nginx
Конфиг изменили, но старый процесс продолжает работать. После правки проверьте, что сервисы действительно перечитали конфигурацию. Иначе вы будете искать несуществующую ошибку в коде.
Проверяют только главную страницу API
/wp-json/ может открываться, а конкретный маршрут — нет. Тестируйте именно тот endpoint, который использует приложение или интеграция.
Отключают все плагины на боевом сайте
Это рискованно и часто не нужно. Лучше сначала отключать только плагины, которые реально влияют на REST API, безопасность и кэш. На staging-копии это делается безопаснее и быстрее.
Путают 403 и 401
401 Unauthorized обычно означает, что аутентификация не прошла. 403 Forbidden чаще говорит о том, что доступ запрещён уже после проверки или запрос заблокирован политикой сервера/плагина.
Используют кэш там, где он не должен работать
Если CDN или page cache кэширует ответы REST API, можно получить странные 403 или устаревшие ответы. Для API обычно нужно исключать /wp-json/ из кэша, особенно если запросы зависят от авторизации.
Безопасность и производительность: что не стоит ломать ради быстрого фикса
Самая частая ошибка — “починить” API полным отключением защиты. Это плохая идея: вы уберёте симптом, но откроете поверхность атаки. Лучше точечно разрешить нужный маршрут, чем отключать фильтрацию целиком.
- проверьте, что
Authorizationпередаётся только там, где это нужно; - исключите REST API из HTML-кэша и агрессивного CDN-кэширования;
- не отключайте весь плагин безопасности, если можно ослабить только одно правило;
- если используете Application Passwords, убедитесь, что соединение идёт по HTTPS;
- ведите лог ошибок на staging, а не на продакшене с открытым debug-выводом.
Если на сайте много дублей, мусорных архивов и лишних технических страниц, имеет смысл отдельно проверить SEO-настройки и чистку служебных URL. В таких случаях помогает не “магия”, а аккуратная настройка индексации и дублей, например через Clearfy Pro: https://wpshop.ru/plugins/clearfy.
Короткий чек-лист перед выкладкой на продакшен
- заголовок
Authorizationдоходит до PHP; - Nginx/Apache не режет запрос;
- нужный REST-маршрут не заблокирован плагином безопасности;
permission_callbackвозвращает ожидаемое значение;- REST API исключён из кэша;
- проверка пройдена через
curlи внешний клиент; - в логах нет повторяющихся
403на тот же endpoint.
Если после всех проверок ошибка остаётся, следующий шаг — сравнить рабочий и нерабочий сервер посимвольно: конфиг веб-сервера, PHP-FPM, список MU-плагинов, правила WAF и настройки CDN. В таких кейсах проблема почти всегда в одном конкретном слое, а не в WordPress как таковом.