CORSでCookieの送受信を許可したい時に確認すること

cors-cookieWEB

Laravelを使ったAPIとSPAでCORSとCookieの設定に悩まされたのでまとめておきます。

クロスオリジンでの通信はそもそもCORSの設定をしていないと怒られるのですが、今回はAccess-Control-Allow-Originをちゃんと指定した上で起きた問題なので少し頭悩ませました。

web周りの知識が欠けているのが原因でしたね。。。

CORSについては下記記事でまとめています👇

【初心者向け】CORSについて理解しよう!

書いていること

・クロスオリジンで認証情報を送る設定(クライアント側とサーバー側)
・Access-Control-Allow-Credentialsとは

クロスオリジンでのCORSとCookieの設定

やりたかったこととしてはLaravel側で認証が済んだ後にSPAにリダイレクトし、SPAからLaravelに対してPOSTリクエストを送るということです。

今回の場合ではapiのMiddlewareではなくwebのMiddlewareを通ります。

やったこと(詰まったポイント)

まず前提として、Laravel側でSPAのOriginからのリクエストは許可するようCORSの設定は済んだ状態です。

こんな感じです。それぞれの設定の詳細はこちら

    'paths' => ['/v1/hoge'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['https://hogehoge.com'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => false,

クライアント側ではリクエストしたいエンドポイントに対してaxiosでPOSTします。

await axios.post('/v1/hoge');

上記でリクエストすると419のエラーが返ってきます。

redirect.vue?5c94:47 Error: Request failed with status code 419
    at createError (createError.js?2d83:16)
    at settle (settle.js?467f:17)
    at XMLHttpRequest.handleLoad (xhr.js?b50d:62)

LaravelのwebミドルウェアではApp\Http\Middleware\VerifyCsrfTokenがよしなにトークンのチェックを行ってくれているためです。

要はSPAからのリクエストが本当に正しいリクエストかチェックしてくれているわけですね。

そのためリクエストを送る時に認証情報をCookieに付与して送信してあげる必要があります。

解決策

クロスオリジンのリクエストでCookieを付与するにはAccess-Control-Allow-Credentialsの設定が必要です。

  • クライアント側(axios)
await axios.post('/v1/hoge',
    {},
    {withCredentials: true} <= 注目
);
  • サーバー側
    'paths' => ['/v1/hoge'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['https://hogehoge.com'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true,  <= 注目

サーバー側ではレスポンスヘッダーにAccess-Control-Allow-Credentials: trueを付与する必要があります。

Access-Control-Allow-Credentials

リクエストのwithCredentialsがtrueの場合にのみ、レスポンスがクライアント側のJavaScriptに公開されます。

参考:Access-Control-Allow-Credentials – HTTP | MDN

その設定はsupports_credentialsをtrueにすることで完了です。

しかし、すべてのオリジンが許可されている場合(allowed_origins*の場合)はsupports_credentialsをtrueにしてもAccess-Control-Allow-Credentials: trueの設定になりません。

これはクライアントとサーバー両方に設定が必要です。

どちらかだけではだめで、僕はクライアント側の設定しかしておらず少し手こずってしまいました。

今回Laravel Sanctumは使っていませんが、Sanctumのページに記載されていました。

コメント

タイトルとURLをコピーしました