Laravel/PHP

[Laravel9×React]サブドメイン間でのCookie共有設定

結論

前提

フロントエンド(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」など他の書き方だとうまくいきませんでした。

参考になりましたら幸いです。今回は以上です。

COMMENT

メールアドレスが公開されることはありません。