10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

session cookieをドメイン、サブドメイン間で共有する方法 rails (API only) + graphql + apollo

Last updated at Posted at 2021-05-18

UkkfkNYM.jpg

問題

domain.tld (frontend) -> login.domain.tld (backend)

  1. frontendとbackendがある
  2. backendはサブドメインだ(その反対、両方でも可)
  3. 両方のドメインでセッションクッキーを保持したい
  4. 認証はgraphql経由(ApolloClient使用)
  5. とりあえずbackendはRailsだ(API only)

解決

  1. corsの問題はクリアしておく
  2. サーバー側のcookie関係なくgraphqlで通信は可能な状態にしておく
  3. API onlyモードのRailsではcookieはデフォルトONではない
  4. セッションcookieももちろんONではない
  5. cookieをONにしてもデフォルトではサブドメインとcookietは共有しない

Rails側

cookieをONにする

application.rb
# dev、prod関係なく全体にcookieは必要だと思うのでここで設定

module App
  class Application < Rails::Application
    ...
    ...
    config.middleware.use ActionDispatch::Cookies
    config.middleware.use ActionDispatch::Session::CookieStore,
                          domain: :all,
                          tld_length: 2,
                          secure: true,
                          same_site: :strict
  end
end

  • domain: :allでどんなサブドメインとも共有
  • tld_length: 自分のドメインがdomain.tld、サブドメインがa.domain.tldだったとして、tld_length: 2domain.tldになる。
    これがbase.domain.tldsub.base.domain.tldとかでbase.domain.tldを軸としてのサブドメイン共有であればtld_length: 3 = base.domain.tldとする。
  • secureとsame_siteは別の話

tld_length

a.b.c.domain.tld
  • tld_length: 2 => domain.tld ベース
  • tld_length: 3 => c.domain.tld ベース
  • tld_length: 4 => b.c.domain.tld ベース
application_controller.rb
class ApplicationController < ActionController::API
  include ActionController::Cookies
end

これがないとcookieは動かない。

sessionをgraphqlで使う

graphql_controller.rb
class GraphqlController < ApplicationController
  def execute
    ...
    ...
    context = {
      session: session,
    }
end

context経由でsessionオブジェクトを渡しておいて、query、mutationでcontext[:session]経由で使う。

subscriptionをActionCable経由で使う場合

ActionCable内でsessionをとってくる事前の設定は全て済んでいるとして

graphql_channel.rb
class GraphqlChannel < ApplicationCable::Channel
  def execute(data)
    ...
    ...
    ...
    context = { channel: self, session: session }

ここでも同じようにcontext経由でsessionオブジェクトを渡す。

Apollo側の設定

You just need to pass the credentials option. e.g. credentials: 'same-origin' as shown below, if your backend server is the same domain or else credentials: 'include' if your backend is a different domain.

linkオブジェクト

  • credentials: include

これだけ

動作確認

domain.tldからbackend.domain.tldへのgraphql呼び出し

https___subsystem_mgbf-2.png

sessionを使うgraphqlを呼んだ時に、こういう風にcookieができていればOK。

10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?