結論
前提
フロントエンド(React)とバックエンド(Laravel)でデプロイ先サーバーが異なり、それぞれ異なるサブドメインを設定している場合を想定しています。
ただしドメインは同じものを使っています。
【例】
フロント:https://example.com(サブドメイン無し)
API:https://api.example.com
また、今回共有するCookieはLaravel Sanctumの「sanctum/csrf-cookie」実施時に設定されるトークンのことになります。
解決策
Laravel側の`.env` ファイルに以下を追加することで解決しました。
SESSION_DOMAIN=".example.com"
※ここまでの対応ではまだReact側からCookieを操作できない可能性があります。React側からCookieを操作したい場合は以下の記事もご参照くださいませ。
はじめに
以下の例のようにドメインが違うとCookieを共有できません。
【例】
・https://api.example1.com
・https://front.example2.com
ドメイン自体が一致していれば、サブドメイン間でCookieを共有できます。が、Laravel9×Reactでの開発でうまくCookieに保存ができなかったので解決策をまとめます。
問題
ログイン状態をCookieに保存して管理するWebアプリを開発しています。ローカル開発環境ではLaravel側からうまくCookieに値を設定できるのですが、どうもサーバーにデプロイするとうまく保存できない様子。
違いがあるとしたらドメインぐらいだな、と思い調査をしましたがなかなか解決できずにいました。もしかしたらサブドメイン間で共有できないのではないか?という疑心暗鬼になりそうでしたが、多くの既存サービスが実装しているはずだよなと諦めずにいろいろと試してみました。
調査
まずLaravelが「Set-Cookie」を設定しているのはどこなのかを特定します。
`vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware`
こちらにある`VerifyCsrfToken.php` に$configの`domain` を参照する記述がありました。
/**
* Create a new "XSRF-TOKEN" cookie that contains the CSRF token.
*
* @param \Illuminate\Http\Request $request
* @param array $config
* @return \Symfony\Component\HttpFoundation\Cookie
*/
protected function newCookie($request, $config)
{
return new Cookie(
'XSRF-TOKEN',
$request->session()->token(),
$this->availableAt(60 * $config['lifetime']),
$config['path'],
$config['domain'],
$config['secure'],
false,
false,
$config['same_site'] ?? null
);
}
この`$config` は「session.php」を参照しているようです。
/**
* Add the CSRF token to the response cookies.
*
* @param \Illuminate\Http\Request $request
* @param \Symfony\Component\HttpFoundation\Response $response
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function addCookieToResponse($request, $response)
{
$config = config('session');
if ($response instanceof Responsable) {
$response = $response->toResponse($request);
}
$response->headers->setCookie($this->newCookie($request, $config));
return $response;
}
session.phpを見てみると、ありました。「domain」
/*
|--------------------------------------------------------------------------
| Session Cookie Domain
|--------------------------------------------------------------------------
|
| Here you may change the domain of the cookie used to identify a session
| in your application. This will determine which domains the cookie is
| available to in your application. A sensible default has been set.
|
*/
'domain' => env('SESSION_DOMAIN'),
`.env` ファイルの「SESSION_DOMAIN」を参照しているようなので、追加します。
.env
SESSION_DOMAIN=".example.com"
これにより無事Laravelで開発したAPI側から、サブドメイン無しのフロントエンド(を表示しているブラウザ)に対してCookieを設定できました。
開発者ツールのストレージ欄で以下のように確認できました。
※冒頭にも書きましたが、ここまでの対応ではまだReact側からCookieを操作できない可能性があります。React側からCookieを操作したい場合は以下の記事もご参照くださいませ。
後日書きます
初期状態の.envにはSESSION_DOMAINは無かった
単純に修正を忘れていたかな、と思ったのですがそもそも初期状態の.envファイルには「SESSION_DOMAIN」が設定されていませんでした。ひとつのサービスを複数のドメイン(サブドメイン)で運用する場合は追加してね、ということなのかなと思います。
あと、設定する値もポイントで「.example.com」(例です)としていますが、「https://example.com」など他の書き方だとうまくいきませんでした。
参考になりましたら幸いです。今回は以上です。