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不正 | codeとmessage |
| 403+HTML | WAF、Webサーバー、セキュリティ機能 | ブロック画面の名称 |
| 404+JSON | ルート・メソッド・IDの誤り | rest_no_routeなど |
| 404+HTML | REST APIへ未到達、URLやRewriteの問題 | サーバーの404ページ |
JSONかHTMLかで、調べる場所が大きく変わります。WordPress形式のJSONが返っていれば、少なくともリクエストはWordPressのREST APIまで到達しています。
今回の検証環境と実測結果
2026年7月25日に、このサイトへWindows PowerShellからリクエストしました。401と404は認証情報なし、403は検証用の購読者ユーザーとアプリケーションパスワードを使っています。
| 検証日 | 2026年7月25日 |
|---|---|
| WordPress | 7.0.2 |
| PHP | 8.4.21 |
| Webサーバー | nginx |
| セキュリティプラグイン | SiteGuard WP Plugin 1.8.7 |
| 確認環境 | Windows PowerShell/curl.exe |
| 403の検証ユーザー | 購読者 |
投稿作成用エンドポイントへPOSTし、認証状態だけを変えて401と403を再現しました。どちらもrest_cannot_createでしたが、HTTPステータスは次のように分かれています。
| 確認内容 | 結果 | WordPressのcode |
|---|---|---|
| 認証なしで投稿作成をPOST | 401 | rest_cannot_create |
| 購読者として投稿作成をPOST | 403 | rest_cannot_create |
| 存在しないREST APIルートをGET | 404 | rest_no_route |
401と403は日本語のメッセージも同じでした。本文だけでなく、HTTPステータスと認証条件をセットで見る必要があります。なお、公開済み投稿を取得する/wp-json/wp/v2/postsへのGETは、未認証でも200になるのが通常です。

最初にREST APIへ到達できるか確認する
いきなり認証設定を変更する前に、REST APIの入口を確認します。ブラウザーで開いても構いませんが、ヘッダーまで見たい場合はcurl.exe -iが分かりやすいです。
curl.exe -i "https://example.com/wp-json/"200とapplication/jsonが返り、namespacesやroutesが含まれていれば、REST APIの入口までは到達しています。
ここで403や404のHTMLが返る場合は、ユーザー名やアプリケーションパスワードより先に、URL、WordPressの設置場所、WebサーバーのRewrite、WAF、セキュリティプラグインを確認します。

対象エンドポイントを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の場合は、次の順番で確認します。
- 認証ヘッダーがリクエストに付いているか
- ユーザー名とアプリケーションパスワードが正しいか
- HTTPSで接続しているか
- プロキシやWebサーバーが
Authorizationヘッダーを落としていないか - 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上で持つ権限の範囲内で動作します。


403+HTMLならWordPressの手前も確認する
403でも、本文がHTMLでWordPressのcodeやdata.statusがない場合は、Webサーバー、WAF、CDN、セキュリティプラグインが返した可能性があります。これは今回の権限不足による403とは別の切り分けです。
- HTML内にWAFやセキュリティ製品の名称がないか
- ホスティング側のWAFログに記録がないか
- セキュリティプラグインのREST API制限が有効でないか
- 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によって修正箇所は別です。


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が返ったときは、次の順で確認すると、認証設定をむやみに変更せずに済みます。


/wp-json/が200+JSONになるか確認する- 200+JSONでなければ、URL、Rewrite、WAF、セキュリティプラグインを確認する
- 200+JSONなら、対象リクエストのContent-Typeと本文を確認する
- 本文がHTMLなら、ステータスとブロック画面を手掛かりに、WebサーバーやWAFなどWordPressの手前を確認する
- 本文がJSONなら、HTTPステータス、
code、messageを確認する - 401なら認証情報・ヘッダー・nonce、403ならユーザー権限・操作権限を確認する
- 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、セキュリティプラグインまで確認範囲を広げます。



コメント