Rails API(サーバサイド)でCookieを作成する方法

Ruby

前回、RailsでセッションとCookieを操作する方法でRailsにおけるセッションとCookieの操作方法について紹介しました。
前回の記事のRailsアプリケーションはモノリス前提でしたが、今回はAPIモードでCookieを作成する方法について紹介します。railsのバージョンは6.0.4を利用しています。

基礎知識について

フロントエンドとバックエンドが分かれた構成のアプリケーションでCookieを作成する方法

「APIのレスポンスでCookieにセットする値を返し、APIから取得した値をフロントでCookieにセットする」という方法と、「Set-Cookiesがヘッダに含まれたレスポンスをAPIで返す(フロントはレスポンスを受け取るだけ)」という方法の2種類があります。

今回は後者の方法についての紹介になります。

Rails API(サーバサイド)でCookieを作成するメリットについて

ITPの影響を受けない

ITP (Intelligent Tracking Prevention)とはプライバシー保護の目的でSafariブラウザに実装されたサイトトラッキングの抑制機能です。

Cookieには自社サーバから発行されるファーストパーティCookie(1st party cookies)と、他社サーバから発行されるサードパーティCookie(3rd party cookies)の2種類があります。
JavaScriptを利用して作成されたファーストパーティCookieの有効期限はITP 2.1では7日間、ITP 2.2では24時間です。1 2

フロントエンド、つまりJavaScriptでCookieを作成する際はITPの影響を受けますが、サーバサイドでCookieを作成する場合は影響を受けません。

フロントエンド(JavaScript)でCookieを操作する必要がなくなるためセキュア

フロントエンドでCookieを作成する場合、JavaScriptでCookieを操作することになります。
JavaScirptによる操作が許可されたCookieの場合、XSS(クロスサイトスクリプティング)の考慮が必要になります。

サーバサイドでCookieを作成することでJavaScriptによる操作を許可しないHttpOnly属性を付与できるためセキュアにCookieのやりとりができます。

デフォルトのRails APIモードではcookiesメソッドが利用できない

RailsアプリケーションでCookieを操作する場合はAction Controllercookiesメソッドを利用します。3

デフォルトのRails APIモードの場合、例えば以下のようなControllerにアクセスするとundefined local variable or method cookies for xxxxというNameErrorが返ってきます。

def index
  cookies[:user_id] = 1
end

Rails APIモードでCookieを作成するためにやること

Rails APIモードでCookieを作成するには以下の2つの設定が必要です。

  • ActionController::Cookiesをinclude
  • ActionDispatch::Cookiesを読み込む

ActionController::Cookiesをinclude

cookiesメソッドが定義されているActionController::Cookiesをincludeします。

app/controllers/application_controller.rb

class ApplicationController < ActionController::API
  include ActionController::Cookies
end

ActionDispatch::Cookiesを読み込む

Rack middlewareのActionDispatch::Cookiesを読み込みます。

config/application.rb

module ExampleApp
  class Application < Rails::Application
    ...
    ...
    config.middleware.use ActionDispatch::Cookies
  end
end

動作確認

Cookieの作成方法

例えば以下のようなControllerにアクセスするとSet-Cookie: user_id=1; path=/がヘッダにセットされたレスポンスが返ってきます。

def index
  cookies[:user_id] = 1
end
$ curl -i http://localhost:3001/

HTTP/1.1 200 OK
(略)
Set-Cookie: user_id=1; path=/
(略)

ブラウザのCookieを確認すると先ほど定義したキーと値がセットされていることがわかります。

Cookieの取得方法

coookie[キー名]あるいはrequest.cookiesでフロントエンドからのリクエストと一緒に送られたCookieを確認できます。

例えば、user_idという値が1のCookieを取得する方法は以下の通りです。

     2: def index
 =>  3:   binding.pry

> cookies[:user_id]
=> "1"

> request.cookies
=> {"user_id"=>"1"}

さいごに

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

参考資料