Laravelを使ったAPIとSPAでCORSとCookieの設定に悩まされたのでまとめておきます。
クロスオリジンでの通信はそもそもCORSの設定をしていないと怒られるのですが、今回はAccess-Control-Allow-Originをちゃんと指定した上で起きた問題なので少し頭悩ませました。
web周りの知識が欠けているのが原因でしたね。。。
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
を付与する必要があります。
その設定はsupports_credentials
をtrueにすることで完了です。
しかし、すべてのオリジンが許可されている場合(allowed_origins
が*
の場合)はsupports_credentials
をtrueにしてもAccess-Control-Allow-Credentials: true
の設定になりません。
これはクライアントとサーバー両方に設定が必要です。
どちらかだけではだめで、僕はクライアント側の設定しかしておらず少し手こずってしまいました。
今回Laravel Sanctumは使っていませんが、Sanctumのページに記載されていました。
コメント