複数の特定オリジンを許可する

複数のフロントエンドドメインがアクセスする必要がある場合のCORS処理。許可リストからAllow-Originを動的に設定するサーバーサイドパターンを学びます。

Basic CORS

詳細な説明

許可リストからの動的オリジン

Access-Control-Allow-Originヘッダーは1つの値(または*)のみ受け付けます。複数のオリジンをカンマ区切りにすることはできません。https://app.example.comhttps://admin.example.comを許可する必要がある場合、サーバーは受信したOriginヘッダーを許可リストと照合し、一致した場合にエコーバックする必要があります。

サーバーロジック(擬似コード)

allowed = ["https://app.example.com", "https://admin.example.com"]
if request.headers["Origin"] in allowed:
    response.headers["Access-Control-Allow-Origin"] = request.headers["Origin"]
    response.headers["Vary"] = "Origin"

Nginx実装

map $http_origin $cors_origin {
    default "";
    "https://app.example.com"   "$http_origin";
    "https://admin.example.com" "$http_origin";
}

if ($cors_origin != "") {
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
    add_header Access-Control-Allow-Credentials "true" always;
    add_header Vary Origin always;
}

Express.js実装

const allowedOrigins = [
  "https://app.example.com",
  "https://admin.example.com",
];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  credentials: true,
}));

なぜVary: Originが重要か

レスポンスがリクエスト元のオリジンによって変わるため、キャッシュはOriginヘッダーをキーとして使用する必要があります。Vary: Originがないと、CDNがapp.example.com向けのレスポンスをキャッシュしてadmin.example.comに配信する可能性があり、ブラウザのオリジンチェックに失敗します。

ユースケース

顧客向け(app.example.com)と社内スタッフ向け(admin.example.com)に別々のフロントエンドアプリを持つ企業で、両方が同じREST APIを消費しています。各オリジンを明示的にホワイトリストに登録する必要があります。

試してみる — CORS Header Builder

フルツールを開く