WordPress REST APIで401・403・404になる原因|レスポンスから切り分ける方法

WordPress REST APIの401・403・404エラーを切り分けるイメージ

WordPress REST APIへ接続したとき、同じように通信へ失敗しても、返ってくるステータスコードは401・403・404とさまざまです。

401なら認証、403なら権限、404ならURLと考えたくなりますが、実際にはそれだけでは切り分けられません。セキュリティプラグインやWAFがWordPressより手前で遮断すると、認証情報が正しくても403になることがあります。

今回は、ちゃあむワークノートのREST APIへ実際にリクエストし、未認証の401、認証済み・権限不足の403、存在しないルートの404を同じ画面で比較しました。どこから確認すればよいか、レスポンス本文も見ながら整理します。

今回の結論

401と403は、エラーメッセージが同じでも意味が異なります。未認証なら401、認証済みでも操作権限がなければ403です。404はURLだけでなく、WordPress形式のJSONに含まれるcodeを確認し、ルートなしと対象データなしを分けます。

目次

401・403・404の違いを先に整理

WordPress本体のREST APIでは、認可エラー時のステータスを決めるrest_authorization_required_code()が用意されています。この関数は、未ログインなら401、ログイン済みなら403を返します。

ただし、REST APIの外側にあるWebサーバー、WAF、CDN、セキュリティプラグインは、別の基準で403や404を返せます。次の表はあくまで最初の手掛かりです。

結果最初に疑うこと本文で確認するもの
401+JSON未認証、認証情報の不備rest_cannot_createなど
403+JSON権限不足、nonce不正codemessage
403+HTMLWAF、Webサーバー、セキュリティ機能ブロック画面の名称
404+JSONルート・メソッド・IDの誤りrest_no_routeなど
404+HTMLREST APIへ未到達、URLやRewriteの問題サーバーの404ページ

JSONかHTMLかで、調べる場所が大きく変わります。WordPress形式のJSONが返っていれば、少なくともリクエストはWordPressのREST APIまで到達しています。

今回の検証環境と実測結果

2026年7月25日に、このサイトへWindows PowerShellからリクエストしました。401と404は認証情報なし、403は検証用の購読者ユーザーとアプリケーションパスワードを使っています。

検証日2026年7月25日
WordPress7.0.2
PHP8.4.21
Webサーバーnginx
セキュリティプラグインSiteGuard WP Plugin 1.8.7
確認環境Windows PowerShell/curl.exe
403の検証ユーザー購読者

投稿作成用エンドポイントへPOSTし、認証状態だけを変えて401と403を再現しました。どちらもrest_cannot_createでしたが、HTTPステータスは次のように分かれています。

確認内容結果WordPressのcode
認証なしで投稿作成をPOST401rest_cannot_create
購読者として投稿作成をPOST403rest_cannot_create
存在しないREST APIルートをGET404rest_no_route

401と403は日本語のメッセージも同じでした。本文だけでなく、HTTPステータスと認証条件をセットで見る必要があります。なお、公開済み投稿を取得する/wp-json/wp/v2/postsへのGETは、未認証でも200になるのが通常です。

WordPress REST APIで未認証の401、購読者の403、存在しないルートの404を比較した結果

最初にREST APIへ到達できるか確認する

いきなり認証設定を変更する前に、REST APIの入口を確認します。ブラウザーで開いても構いませんが、ヘッダーまで見たい場合はcurl.exe -iが分かりやすいです。

curl.exe -i "https://example.com/wp-json/"

200とapplication/jsonが返り、namespacesroutesが含まれていれば、REST APIの入口までは到達しています。

ここで403や404のHTMLが返る場合は、ユーザー名やアプリケーションパスワードより先に、URL、WordPressの設置場所、WebサーバーのRewrite、WAF、セキュリティプラグインを確認します。

WordPress REST APIのインデックスで200とapplication/jsonを確認した結果

対象エンドポイントをOPTIONSで確認する

REST APIの入口が正常なら、次は対象エンドポイントへOPTIONSを送ります。ルートが登録されていれば、利用できるメソッドや引数の情報が返ります。

curl.exe -i -X OPTIONS "https://example.com/wp-json/wp/v2/posts"

WordPressの公式ドキュメントでは、ルートはwp/v2/posts/123のようなURI、エンドポイントはそのルートに対するGET・POST・DELETEなどの処理として説明されています。URLが合っていても、HTTPメソッドが登録されていなければrest_no_routeになる点に注意します。

401 Unauthorizedを切り分ける

401は、WordPressが現在のリクエストを未認証として扱っているときに返る代表的な結果です。今回、認証なしで投稿作成用エンドポイントへPOSTしたところ、次のJSONが返りました。

{
  "code": "rest_cannot_create",
  "message": "このユーザーとして投稿を編集する権限がありません。",
  "data": {
    "status": 401
  }
}

401の場合は、次の順番で確認します。

  1. 認証ヘッダーがリクエストに付いているか
  2. ユーザー名とアプリケーションパスワードが正しいか
  3. HTTPSで接続しているか
  4. プロキシやWebサーバーがAuthorizationヘッダーを落としていないか
  5. Cookie認証ならX-WP-Nonceを送っているか

WordPress 5.6以降は、外部アプリからのREST API認証にアプリケーションパスワードを利用できます。通常のログインパスワードを外部ツールへ保存するのではなく、用途別に発行したアプリケーションパスワードを使います。

認証だけを確認するなら、投稿を作成せず、現在のユーザーを取得するエンドポイントが安全です。

curl.exe --user "USERNAME:APPLICATION_PASSWORD" `
  "https://example.com/wp-json/wp/v2/users/me?context=edit"

WordPress内のJavaScriptからCookie認証を使う場合は、wp_rest用のnonceをX-WP-Nonceヘッダーなどで送ります。公式ドキュメントでは、nonceがない場合、ログイン済みでも現在のユーザーをID 0へ変更し、未認証として扱うと説明されています。

未認証の401は、先ほどの比較キャプチャに含めています。認証情報を付けたつもりなのに401になる場合は、アプリケーションパスワードの値だけでなく、Authorizationヘッダーがサーバーまで届いているかも確認します。

403 Forbiddenを切り分ける

今回の403は、購読者として認証した状態で投稿作成を試したときに返りました。認証自体は通っていますが、購読者には投稿を作成する権限がないためです。

ボンボン

401とメッセージが同じでも、403なら「認証できた後の権限不足」なんだね。

403+JSONならユーザー権限を確認する

WordPress形式のJSONが返っている場合は、認証したユーザーと実行しようとした操作を照らし合わせます。今回のようにrest_cannot_createなら、投稿作成に必要な権限がありません。

  • 認証したユーザーの権限グループは何か
  • 対象の投稿タイプを作成・編集できるか
  • 他ユーザーが作成した投稿を編集しようとしていないか
  • 独自APIのpermission_callbackを満たしているか
  • Cookie認証ならX-WP-Nonceが正しいか

アプリケーションパスワードを発行しただけでは、ユーザーの権限が増えるわけではありません。外部アプリは、そのアプリケーションパスワードを発行したユーザーがWordPress上で持つ権限の範囲内で動作します。

WordPressの検証用ユーザーにREST API用アプリケーションパスワードを追加する画面

403+HTMLならWordPressの手前も確認する

403でも、本文がHTMLでWordPressのcodedata.statusがない場合は、Webサーバー、WAF、CDN、セキュリティプラグインが返した可能性があります。これは今回の権限不足による403とは別の切り分けです。

  1. HTML内にWAFやセキュリティ製品の名称がないか
  2. ホスティング側のWAFログに記録がないか
  3. セキュリティプラグインのREST API制限が有効でないか
  4. GET・POST・OPTIONSで結果が変わるか

WAFやセキュリティ機能をサイト全体で無効にしたまま運用するのは避けます。ブロック元を特定し、必要な通信だけを安全に許可できるか確認します。

404 Not Foundを切り分ける

404も、JSONかHTMLかで考え方が変わります。今回、存在しない独自ルートへアクセスすると、次のJSONが返りました。

{
  "code": "rest_no_route",
  "message": "URL とリクエストメソッドに一致するルートが見つかりませんでした。",
  "data": {
    "status": 404
  }
}

rest_no_routeでは、URLだけでなくHTTPメソッドも確認します。GET用のルートへ未対応のメソッドを送った場合も、「ルートなし」として扱われることがあります。

rest_no_routeで確認すること

  • wp-json以降のnamespace、バージョン、resource名
  • GET・POST・PUT・PATCH・DELETEなどのHTTPメソッド
  • エンドポイントを追加するプラグインが有効か
  • 独自ルートをrest_api_initで登録しているか
  • カスタム投稿タイプのshow_in_restが有効か

ルートはあるがIDが存在しない404もある

存在しない投稿IDへアクセスした場合は、同じ404でもrest_post_invalid_idが返りました。

{
  "code": "rest_post_invalid_id",
  "message": "無効な投稿 ID です。",
  "data": {
    "status": 404
  }
}

この場合はルート登録やRewriteではなく、指定したID、投稿タイプ、削除済みかどうかを確認します。404という数字が同じでも、JSONのcodeによって修正箇所は別です。

WordPress REST APIでルートなしと無効な投稿IDの404を比較した結果

404+HTMLなら別URLも試す

/wp-json/自体が404のHTMLになる場合は、WordPressをサブディレクトリへ設置していないか、サイトURLが正しいか、WebサーバーのRewriteが動いているかを確認します。

WordPress公式ドキュメントでは、pretty permalinkを使わないサイト向けに、?rest_route=/wp/v2/posts/123形式も案内されています。次の2つを比較すると、パス形式だけの問題かを切り分けられます。

curl.exe -i "https://example.com/wp-json/wp/v2/posts"
curl.exe -i "https://example.com/?rest_route=/wp/v2/posts"

迷ったときの確認順

401・403・404が返ったときは、次の順で確認すると、認証設定をむやみに変更せずに済みます。

WordPress REST APIの401・403・404エラーを切り分ける確認フロー
  1. /wp-json/が200+JSONになるか確認する
  2. 200+JSONでなければ、URL、Rewrite、WAF、セキュリティプラグインを確認する
  3. 200+JSONなら、対象リクエストのContent-Typeと本文を確認する
  4. 本文がHTMLなら、ステータスとブロック画面を手掛かりに、WebサーバーやWAFなどWordPressの手前を確認する
  5. 本文がJSONなら、HTTPステータス、codemessageを確認する
  6. 401なら認証情報・ヘッダー・nonce、403ならユーザー権限・操作権限を確認する
  7. 404ならOPTIONSでルートとHTTPメソッドを確認し、通常URLと?rest_route=形式、namespace、バージョン、IDも比較する

APIのレスポンスをJSONとして処理した結果、Unexpected token '<'が出ている場合は、HTMLが返っていないかを先に確認します。Networkパネルでの見方は、次の関連記事で詳しくまとめています。

ChatGPTとWordPressをWPVibeで連携し、実際に下書きを作る流れは、次の関連記事で紹介しています。REST APIの認証・権限・セキュリティ設定が、外部連携の成否へそのまま影響します。

まとめ

WordPress REST APIの401・403・404は、ステータスコード、レスポンス本文、認証条件を組み合わせて確認します。

今回の検証では、投稿作成用の同じエンドポイントに対して、認証なしでは401、購読者として認証すると403になりました。どちらもrest_cannot_createでメッセージも同じでしたが、401は未認証、403は認証後の権限不足です。

存在しないルートでは、404とrest_no_routeが返りました。同じ404でもrest_post_invalid_idなら、ルートではなく指定した投稿IDを確認します。HTMLが返った場合は、WordPressの設定だけでなく、WebサーバーやWAF、セキュリティプラグインまで確認範囲を広げます。

参考リンク

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

ちゃあむのアバター ちゃあむ エンジニア

Web開発やSaaS(ServiceNow、Salesforce)、業務システムに携わる、猫と食べることが大好きなインドア系ITエンジニアです。

コメント

コメントする


目次