2026年7月7日

2026年7月7日

Nginxで外部認証サービスを連携するauth_requestの設定方法

はじめに

Nginxのauth_requestモジュールを使って独自の認証サーバーと連携したい・JWTトークンやCookieを使ったリクエスト認可をNginxレベルで行いたい・WordPress管理画面やAPIエンドポイントをカスタム認証で保護したいといった問題の解決方法を解説します。

症状・原因

  • auth_requestの設定はしたがsubrequest failedエラーが出る(認証サーバーのURLが正しくない)
  • 認証サーバーが200以外を返すと403になるが、エラーの詳細がクライアントに返らない
  • 認証ヘッダーをバックエンドに引き継げない(auth_request_setの使い方がわからない)
  • auth_requestモジュールがNginxに組み込まれていない

解決手順

ステップ1:auth_request モジュールの確認

# ✅ auth_request モジュールが有効か確認
nginx -V 2>&1 | grep auth_request
# → --with-http_auth_request_module ← 組み込み済み

# ✅ Ubuntu/Debian の場合は標準で組み込まれている
# CentOS の場合は nginx-plus または独自ビルドが必要

# ✅ 認証サーバーの動作テスト(事前に)
curl -sI http://localhost:8081/auth
# → HTTP/1.1 200 OK ← 認証成功
# → HTTP/1.1 401 Unauthorized ← 認証失敗

# ✅ 認証サーバーがCookieで認証する場合
curl -sI -b "session=valid_session" http://localhost:8081/auth
# → HTTP/1.1 200 OK ← Cookie認証成功

ステップ2:基本的な auth_request 設定

# ✅ /etc/nginx/sites-available/wordpress.conf

server {
    listen 443 ssl http2;
    server_name example.com;

    root /var/www/html;

    # ✅ 認証サーバーのエンドポイント(内部のみ)
    location = /internal/auth {
        internal;  # 外部からの直接アクセスを禁止
        proxy_pass http://localhost:8081/auth;
        proxy_pass_request_body off;  # ボディは送らない(ヘッダーのみ)
        proxy_set_header Content-Length "";

        # ✅ 元のリクエスト情報を認証サーバーに送る
        proxy_set_header X-Original-URI $request_uri;
        proxy_set_header X-Original-Method $request_method;
        proxy_set_header X-Real-IP $remote_addr;

        # ✅ Cookie をそのまま転送
        proxy_set_header Cookie $http_cookie;

        # ✅ Authorization ヘッダーを転送(JWT認証)
        proxy_set_header Authorization $http_authorization;
    }

    # ✅ 認証が必要なエリア
    location /wp-admin/ {
        auth_request /internal/auth;
        auth_request_set $auth_status $upstream_status;

        # ✅ 認証失敗(401)のカスタムエラー
        error_page 401 = @unauthorized;
        error_page 403 = @forbidden;

        try_files $uri $uri/ /index.php?$args;
    }

    # ✅ 認証済みユーザーの情報をバックエンドに引き継ぐ
    location ~ \.php$ {
        auth_request /internal/auth;
        auth_request_set $user_id $upstream_http_x_user_id;
        auth_request_set $user_role $upstream_http_x_user_role;

        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        # ✅ 認証情報をPHPに渡す
        fastcgi_param HTTP_X_USER_ID $user_id;
        fastcgi_param HTTP_X_USER_ROLE $user_role;
    }
}

ステップ3:JWT 認証と連携する

# ✅ JWT 検証サービスと連携(Node.js/Goなどの認証マイクロサービス)
upstream jwt_auth_service {
    server 127.0.0.1:3001;
    keepalive 10;
}

server {
    location = /internal/jwt-auth {
        internal;
        proxy_pass http://jwt_auth_service/validate;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header Authorization $http_authorization;
        proxy_set_header X-Original-URI $request_uri;
    }

    # ✅ API エンドポイントを JWT で保護
    location /api/ {
        auth_request /internal/jwt-auth;

        # ✅ JWT から取得したユーザー情報を引き継ぐ
        auth_request_set $jwt_user_id   $upstream_http_x_user_id;
        auth_request_set $jwt_user_name $upstream_http_x_user_name;

        proxy_pass http://api_backend/;
        proxy_set_header X-User-ID   $jwt_user_id;
        proxy_set_header X-User-Name $jwt_user_name;

        # ✅ 認証失敗時のエラーレスポンス(JSON)
        error_page 401 = @api_unauthorized;
    }

    location @api_unauthorized {
        default_type application/json;
        return 401 '{"error":"Unauthorized","message":"Valid JWT token required"}';
    }
}

ステップ4:認証エラーのハンドリング

# ✅ 認証失敗時のリダイレクトを設定
server {
    # ✅ 未認証(401): ログインページにリダイレクト
    location @unauthorized {
        add_header WWW-Authenticate 'Bearer realm="example.com"';
        return 302 /login?redirect=$request_uri;
    }

    # ✅ 権限なし(403): エラーページを表示
    location @forbidden {
        root /var/www/html;
        try_files /403.html =403;
    }

    # ✅ 認証サーバーがダウンした場合のフォールバック
    location = /internal/auth {
        internal;
        proxy_pass http://auth_service/validate;

        # ✅ 認証サーバーがエラーの場合の処理
        # proxy_intercept_errors on でカスタムエラーを定義
        proxy_intercept_errors off;

        # ✅ タイムアウト設定(認証は高速であるべき)
        proxy_connect_timeout 2s;
        proxy_read_timeout    5s;
    }
}

ステップ5:WordPress に auth_request を統合する

# ✅ WordPress の REST API を外部認証で保護
server {
    # ✅ REST API は JWT 認証必須
    location ~ ^/wp-json/my-plugin/ {
        auth_request /internal/jwt-auth;
        auth_request_set $wp_user_id $upstream_http_x_wp_user_id;

        try_files $uri $uri/ /index.php?$args;
    }

    # ✅ WP REST API のユーザー一覧は認証必須(セキュリティ)
    location = /wp-json/wp/v2/users {
        auth_request /internal/auth;
        try_files $uri $uri/ /index.php?$args;
    }

    # ✅ WordPress のフロントページは認証不要
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}
# ✅ auth_request の動作確認
# 有効なトークンでアクセス
curl -H "Authorization: Bearer valid_jwt_token" \
    https://example.com/api/data
# → 200 OK

# 無効なトークンでアクセス
curl -H "Authorization: Bearer invalid_token" \
    https://example.com/api/data
# → 401 Unauthorized {"error":"Unauthorized",...}

# ✅ Nginx のデバッグログで auth_request を追跡
sudo nginx -c /etc/nginx/nginx.conf -g "error_log /tmp/nginx_debug.log debug;"
sudo tail -f /tmp/nginx_debug.log | grep "auth_request"

注意事項

  • auth_requestのサブリクエストにproxy_pass_request_body offを必ず設定してください。設定しないと元のリクエストボディ(大きなファイルアップロードなど)が認証サーバーにも送られてしまい、パフォーマンスが低下します
  • 認証サーバーは必ず高速に応答する必要があります(100ms以内が目標)。認証サーバーがスローになると全リクエストが影響を受けます。proxy_connect_timeout 2sproxy_read_timeout 5sで適切な上限を設定してください

まとめ

Nginxのauth_request設定は①nginx -V--with-http_auth_request_moduleを確認・認証サーバーの動作テスト、②location = /internal/auth { internal; proxy_pass ... }で内部認証エンドポイント設定・proxy_pass_request_body offでボディ不送信・CookieとAuthorizationヘッダーを転送、③JWTサービスと連携・auth_request_setで認証レスポンスヘッダーを変数に格納・バックエンドにユーザー情報を引き継ぎ、④認証失敗(401)でログインページにリダイレクト・権限なし(403)でエラーページ・認証サーバーに短いタイムアウトを設定、⑤WordPress REST APIを選択的に保護・フロントページは認証不要・デバッグログでauth_requestの動作確認の手順で設定します。

お気軽にご相談ください

お見積りへ お問い合わせへ