rack-corsとfetch APIを利用したCookieの送受信方法

バックエンド

オリジン間リソース共有 (Cross-Origin Resource Sharing, CORS)において、Rails APIとフロントのfetch API間でCookieを送受信できるようにする方法について紹介します。

rack-corsの設定

rack-corsはRailsアプリケーションのCORS設定用のgemです。
CORSでCookieを送信する場合はcredentials: trueを追加します。

config/initializers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  unless Rails.env.production?
    allow do

      ### 『localhost』『localhost:[ポート番号]』『[サブドメイン].local.example-dev.com』のオリジンを許可
      origins(['localhost', /localhost:\d+\Z/, /(.+).local.example-dev.com\Z/])

      resource '*',
        headers: :any,
-       methods: [:get, :post, :put, :patch, :delete, :options, :head]
+       methods: [:get, :post, :put, :patch, :delete, :options, :head],
+       credentials: true
    end
  end
end

上記の設定により、レスポンスヘッダのSet-CookieにCookieがセットされます。
credentials: trueがないとSet-CookieにCookieがセットされないため、フロント(ブラウザ)はCookieの取得ができません。

fetch APIの設定

fetch APIでCookieを取得する場合はcredentials: 'include'を追加します。

### APIのドメインが『api.local.example-dev.com』の場合
- fetch("http://api.local.example-dev.com/[エンドポイント名]")
+ fetch("http://api.local.example-dev.com/[エンドポイント名]", { credentials: 'include' })

Rails API側のCORS設定でcredentials: trueをしていてもfetch APIでcredentials: 'include'を追加しなければ、Set-CookieにセットされたCookieをブラウザにセットできません。

逆に、fetch APIでcredentials: 'include'を設定しているのにRails API側のCORS設定でcredentials: trueをしていない場合はAccess to fetch at 'http://[APIのエンドポイント]' from origin 'http://[フロントのエンドポイント]' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.というエラーがブラウザに発生します。

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!

参考記事