Если фронтенд, мобильное приложение, редактор блоков или внешний сервис внезапно перестали получать данные из WordPress по REST API, чаще всего в логах или в ответе сервера всплывают 401 Unauthorized или 403 Forbidden. На практике это не одна проблема, а несколько разных сценариев: запрос не проходит авторизацию, его режет серверный WAF, плагин безопасности, кэш или неверные заголовки на прокси.
Ниже — рабочий порядок диагностики и исправления. Он подходит для случаев, когда API нужен для интеграции, автоматизации, Gutenberg, headless-фронтенда или внешнего сервиса, который ходит в /wp-json/.
Что именно ломается: 401 или 403
Сначала важно не смешивать эти ошибки. Они похожи внешне, но причины обычно разные.
401 Unauthorized
Обычно означает, что запрос требует авторизации, но WordPress не получил валидные данные для входа. Это может быть:
- неверный Application Password;
- отсутствующий заголовок
Authorization; - проблема с Basic Auth на уровне nginx/Apache;
- плагин, который ожидает nonce и не получает его.
403 Forbidden
Чаще всего запрос дошёл до сайта, но был запрещён. Причины обычно такие:
- плагин безопасности блокирует REST API;
- WAF/ModSecurity режет запрос по сигнатуре;
- сервер не пропускает определённые методы или заголовки;
- пользователю не хватает прав на конкретный endpoint.
Диагностика проблемы: с чего начать
Не начинайте с правки кода, пока не поймёте, где именно запрос ломается. Самый быстрый путь — проверить ответ напрямую и сравнить его с запросом из браузера или приложения.
1. Проверьте сам endpoint
Откройте в браузере или через curl базовый endpoint:
curl -i https://example.com/wp-json/Если даже этот адрес отдаёт не JSON, а редирект, HTML-страницу ошибки или 403, проблема уже на уровне сервера, кэша или безопасности.
2. Посмотрите, что происходит с авторизацией
Для защищённого маршрута проверьте запрос с заголовком авторизации. Если используете Application Passwords, запрос должен уходить с Basic Auth:
curl -i -u username:'application-password' https://example.com/wp-json/wp/v2/users/meЕсли здесь 401, а в браузере всё работает, значит проблема в передаче заголовка Authorization или в способе авторизации.
3. Посмотрите логи сервера и плагинов
Ищите не только PHP-ошибки. Для 403 часто полезнее:
- access/error log nginx или Apache;
- логи ModSecurity, если он включён;
- журнал плагина безопасности;
- ответы кэширующего слоя, если сайт за Cloudflare или reverse proxy.
Пошаговое решение для 401: авторизация не проходит
Если проблема именно в 401, начинайте с самого частого: заголовок Authorization не доходит до PHP.
Проверьте передачу Authorization на сервере
На некоторых конфигурациях nginx, PHP-FPM или Apache заголовок теряется до WordPress. Для nginx часто помогает явная прокидка заголовка в FastCGI-конфиге:
fastcgi_param HTTP_AUTHORIZATION $http_authorization;Если у вас Apache в связке с PHP-FPM, убедитесь, что заголовок не обрезается прокси-слоем или правилами виртуального хоста. Важно не копировать чужую конфигурацию вслепую: сначала проверьте, что проблема действительно в заголовке.
Проверьте Application Passwords
Если вы используете встроенные Application Passwords, убедитесь, что:
- пользователь существует и не удалён;
- пароль приложения введён без лишних пробелов;
- у пользователя есть нужная роль для конкретного endpoint;
- запрос идёт по HTTPS, а не по HTTP.
Для теста можно временно запросить данные текущего пользователя. Если это работает, а ваш endpoint нет, значит проблема не в общей авторизации, а в правах на маршрут.
Проверьте код, если endpoint свой
Если вы регистрируете свой REST-маршрут, не забывайте о callback для проверки прав. Типичная ошибка — слишком жёсткий permission_callback или его отсутствие.
add_action('rest_api_init', function () {
register_rest_route('myplugin/v1', '/items', [
'methods' => 'GET',
'callback' => 'myplugin_get_items',
'permission_callback' => function () {
return current_user_can('read');
},
]);
});
function myplugin_get_items(WP_REST_Request $request) {
return rest_ensure_response([
'items' => [],
]);
}Если permission_callback возвращает false, WordPress честно отдаст 401 или 403 в зависимости от контекста. Для публичного endpoint используйте __return_true, но только если данные действительно можно показывать всем.
Пошаговое решение для 403: запрос блокируется
С 403 чаще всего виноват не WordPress как таковой, а защита на пути запроса. Здесь полезно сравнить варианты, потому что «отключить всё» — плохая стратегия.
| Подход | Когда подходит | Минус |
|---|---|---|
| Плагин безопасности | Если блокирует только REST API для гостей или отдельных ролей | Можно случайно открыть лишнее |
| Правка сервера/WAF | Если запрос режется ModSecurity, Cloudflare или nginx | Нужен доступ к конфигу и логам |
| Код endpoint'а | Если проблема в правах на конкретный маршрут | Не решает внешнюю блокировку |
Проверьте плагины безопасности
Некоторые плагины умеют ограничивать REST API для неавторизованных пользователей или даже для части маршрутов. Если после деактивации плагина на тестовой копии запрос начинает работать, ищите конкретную настройку, а не оставляйте сайт без защиты.
Вместо полного отключения лучше:
- разрешить нужный endpoint;
- ограничить доступ по роли;
- добавить исключение для конкретного маршрута;
- проверить, не блокируется ли
/wp-json/целиком.
Проверьте WAF и ModSecurity
Если сервер или CDN возвращает 403 до WordPress, в PHP-логах может не быть ничего. Тогда смотрите серверные логи. Часто блокируются:
- нестандартные заголовки;
- JSON-тело с «подозрительными» строками;
- методы
POST,PUT,DELETE; - запросы с авторизацией через Basic Auth.
В таких случаях правильнее точечно ослабить правило для нужного маршрута, чем отключать защиту целиком.
Если REST API ломает кэш или прокси
Иногда проблема выглядит как 401/403, но на деле ответ отдаёт кэширующий слой. Это особенно заметно, если:
- в браузере один ответ, а в
curlдругой; - после очистки кэша всё работает временно;
- запросы к
/wp-json/попадают под общие правила кэширования страниц.
Проверьте, что /wp-json/ и авторизованные запросы не кэшируются как обычные HTML-страницы. Для API-ответов обычно нужны отдельные правила исключения.
Что исключить из кэша
/wp-json/и все его подмаршруты;- запросы с заголовком
Authorization; - страницы админки и AJAX-эндпоинты;
- ответы, зависящие от пользователя.
Проверка результата после исправления
Не ограничивайтесь тем, что «ошибка исчезла в браузере». Проверьте сценарий так, как его использует реальный клиент.
Минимальный чек-лист
- endpoint отвечает нужным кодом:
200,401или403там, где это ожидается; - авторизованный запрос проходит с теми же заголовками, что и в приложении;
- неавторизованный запрос не открывает лишние данные;
- ответ не кэшируется на уровне CDN или reverse proxy;
- в логах больше нет повторяющихся блокировок.
Для быстрой проверки удобно сравнить заголовки ответа:
curl -i https://example.com/wp-json/wp/v2/posts
curl -i -u username:'application-password' https://example.com/wp-json/wp/v2/users/meЕсли первый запрос публичный, а второй авторизованный, вы сразу увидите, где меняется код ответа и какие заголовки возвращает сервер.
Частые ошибки и как их исправить
Отключили REST API целиком ради безопасности
Это грубый подход. Он ломает редактор блоков, интеграции и внешние сервисы. Вместо полного отключения ограничьте доступ к конкретным маршрутам или ролям.
Проверяют только WordPress, а не сервер
Если 403 приходит от WAF или CDN, правка PHP-кода ничего не изменит. Сначала смотрите заголовки ответа и логи на уровне веб-сервера.
Забывают про HTTPS
Application Passwords и Basic Auth должны использоваться по HTTPS. Иначе вы получаете не только ошибки авторизации, но и риск утечки учётных данных.
Ставят кэш на авторизованные запросы
Это приводит к странным симптомам: один пользователь видит чужой ответ, другой получает 403 из-за устаревшего токена или заголовков. Для REST API с авторизацией кэш нужен очень аккуратно и не всегда вообще нужен.
Пишут слишком жёсткий permission_callback
Если callback проверяет не ту capability или не тот контекст, маршрут будет недоступен даже для админа. Проверяйте логику прав отдельно от логики данных.
Практические советы по безопасности и производительности
Когда REST API уже работает, не оставляйте конфигурацию в «разрешить всё». Лучше сразу зафиксировать безопасный вариант.
- Для внешних интеграций используйте отдельного пользователя с минимально нужной ролью.
- Не храните Application Password в публичных репозиториях или в JS-коде фронтенда.
- Если endpoint публичный, ограничьте объём данных и не отдавайте лишние поля.
- Проверьте, не создаёт ли маршрут тяжёлые запросы к базе на каждый вызов.
- Если API используется часто, подумайте о кэшировании на уровне приложения, а не через общий HTML-кэш.
Если вам нужно одновременно почистить сайт от лишних дублей, настроить технические SEO-правила и убрать часть мусора из админки, иногда удобнее собрать это в один набор инструментов, чем держать несколько конфликтующих плагинов. Например, для части задач по чистке и SEO можно посмотреть Clearfy Pro, но он не заменяет диагностику сервера и не чинит проблемы с заголовками сам по себе.
Главная мысль простая: 401 почти всегда про авторизацию, 403 — про запрет на пути запроса. Если разделить эти сценарии и проверить сервер, кэш, плагины безопасности и права маршрута по отдельности, REST API обычно чинится без лишних отключений и без риска открыть сайт шире, чем нужно.