やりたかったこと
以下の条件を満たすアプリケーションでCookieを設定したい
- フロントサイト(ブラウザのナビゲーションバー)のURLとバックエンドのURLが異なる
- フロントサイトからはAjaxによるリクエストを送信し、サーバーは
REST APIを返却するSPAアプリケーションの構成
発生した(解決したかった)現象
Ajaxリクエストのレスポンスで Cookie が設定できない。
Chrome のデベロッパーツールを使用しても特にエラーは出力されないが、なぜか_Cookie_が設定されない。
結論
時間のない方は結論の部分だけ設定してみて下さい。
以下を設定することでクロスサイトでCookieを設定する事ができる
- フロントアプリケーションの設定
-
XMLHttpRequest.withCredentialsにtrueを設定する[^1]
-
- バックエンドアプリケーションの設定
- レスポンスヘッダーに
access-control-allow-credentialsにtrueを設定する[^2] - レスポンスヘッダーに
access-control-allow-originでフロントアプリケーションのURLを設定する[^3]- ['localhost:4000', "*"]の様な値でOK。ワイルドカードのみではいけない
- Cookieを設定する際に
SameSiteポリシーをNoneにする[^5]
- レスポンスヘッダーに
XMLHttpRequest.withCredentials[^1]
XMLHttpRequestは**別のドメインからのCookieをデフォルトでは受付けていません。**
ただし、withCredentialsにtrueを設定している場合、Cookieを受け付けることが出来ます。
また、この設定は同じサイトのリクエストには影響を与えません。
なので、開発環境だけクロスサイトになる様な環境でも特に考慮せずに利用できます。
Mozillaの解説
XMLHttpRequest from a different domain cannot set cookie values for their own domain unless withCredentials is set to true before making the request
access-control-allow-credentials[^2]
リクエストにCredentialsの設定が含まれている場合に、レスポンスをJavaScriptに教えるかどうかを指示するもの
access-control-allow-origin[^3]
指定されたOriginからのリクエストを受け付けることが出来るかを表すもの
ただし、ワイルドカードを指定した場合はCredentialsの設定はサポートされない[^4]
SameSite policy[^5]
- Lax
- モダンブラウザーのdefaultのポリシー
- 以下の何れかの場合にCookieの送信が許可される
- トップレベルナビゲーション(ブラウザーのナビゲーションバー)と同一の場合
- GETリクエストの場合
- Strict
- トップレベルナビゲーション(ブラウザーのナビゲーションバー)と同一の場合のみ送信される
- None
- Cookieは全ての状況で送信される
今回実験している中で分かったこととしては、サブドメインの場合にStrictを設定してもブラウザーにCookieを設定することは出来る。また、Cookieの送信も行われる。
トップレベルナビゲーションのURLとDomainが異なる場合、Noneのポリシーの場合しかCookieを設定することは出来ない。
LaxとStrictはクロスサイトではブラウザーにCookieを設定することができないポリシーとなる。
[^1]https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
[^2]https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
[^3]https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
[^4]https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials
[^5]https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite