Shopify App Node で使われる2つの HTTP Cookie
背景
昨今の 3rd party cookie 規制強化の流れで Shopify App で利用する認証 cookie も影響を受けて、2020年に Shopify Embedded App が受け取る Shopify Admin の認証情報を cookie に依存しない実装に変わりました。
https://github.com/Shopify/shopify-app-template-node/pull/493
具体的には、 Shopify Admin に embedded されたアプリケーションは、Shopify App Bridge を経由して、親 frame である Shopify Admin のセッション情報(id や shop の url) を JWT の形式で受け取ります。
疑問
とはいえ、Shopify App Node を動かしてみるといくつか Cookie を使ってるようです。
気になったので、ここで使われてる Cookie が何に利用されるものなのか調査しました。
shopify_app_session
アプリケーションのセッション情報を Cookie に保存する際の cookie の名前です。
Shopify App Node が shopify-node-api を利用して OAuth プロセスで取得したアクセストークン等のセッション情報をSessionStorageに保存します。これは、 /auth/callback
のエンドポイント内の Shopify.Auth.validateAuthCallback で行われるため、この Cookie 名は Shopify App Node を検索してもヒットしません。
先程説明した通り、embedded app は 親 frame である Shopify Admin からもらったセッション情報(主に user id や shop の url など アクセストークン以外の情報)をJTW形式でもらいます。
JWT の user id, shop url と Shopify_app_session
の cookie に紐づくアプリケーションのセッション情報をSessionStorageから取り出し、user id / shop url などが同じである場合、また有効期限内である場合、有効なセッションとして扱います。
shopify_top_level_oauth
先程説明した shopify_app_session
の セッション Cookie を保存するためには 1st party cookie にする必要があります。
つまり、embedded app のように iframe に埋め込まれるアプリケーションだったとしても、OAuth 認証をする場合はそのリクエストは iframe の外側 で行う必要があります。
/auth/
で OAuth を始める際にそのリクエストが iframe の外側からなのか、それとも内側からなのか判定して、外側の場合にエラーを返すような実装をしたいところですが、HTTP リクエストからそのリクエスト元が iframe の内側なのか
を判定することはできません。 Shopify App Node ではそれを Cookie の sameSite
属性をうまく利用して判定しています。
Shopify App Node の server/middleware/auth.js が該当コードです。
以下、その処理の説明になります。
/auth
へのリクエストが iframe の外側からの場合
- STEP1:
/auth
にリクエスト- 最初は
shopify_top_level_oauth
の cookie が存在しないので/auth/top-level
にリダイレクト
- 最初は
- STEP2:
/auth/top-level
shopify_top_level_oauth
の cookie をsamesite=strict
で発行- また、 JavaScript を返却し browser で実行
- iframe の 外側なので(
window.top === window.self
で判定)/auth
にリダイレクト
- iframe の 外側なので(
- STEP3:
/auth
/auth/top-level
が iframe の外側で、そこから/auth
へリダイレクトした場合、/auth
でshopify_top_level_oauth
の cookie が読めるので、認証処理を開始できる- つまり、iframe の外側にいることの確認が取れたことになる
/auth
へのリクエストが iframe の内側からの場合
- STEP1:
/auth
にリクエスト- 最初は
shopify_top_level_oauth
の cookie が存在しないので/auth/top-level
にリダイレクト
- 最初は
- STEP2:
/auth/top-level
shopify_top_level_oauth
の cookie をsamesite=strict
で発行- また、 JavaScript を返却し browser で実行
- iframe の 内側なので App Bridge のリダイレクト機能を利用して iframe の親 window で
/auth/top-level
にリダイレクト /auth
にリダイレクトしない理由は、iframe の内側からのリクエストに対してsamesite=strict
で発行した cookie は ブラウザに保存されれないためです
- iframe の 内側なので App Bridge のリダイレクト機能を利用して iframe の親 window で
- STEP3:
/auth/top-level
- iframe の 外側からのリクエストでまた同様に
shopify_top_level_oauth
の cookie をsamesite=strict
で発行 - 以降は、
/auth へのリクエストが iframe の外側からの場合
と同じになる
- iframe の 外側からのリクエストでまた同様に
以上のように、iframe の 内側か、外側かの判定はブラウザ側でして、その結果の判断は samesite=strict
で発行された cookie の有無によって行われている。