はじめに
複数のブランドをECサイトで展開していると、いずれ必ず出てくる相談があります。「サイトごとに会員登録が別々なのは不便では?」というものです。
今回扱うのは、1つのShopifyストア(商品や会員データを管理する裏側の仕組み)を共有しながら、見た目もURLも別々の3つのブランドサイトを運営しているケース。フロント側はいずれもヘッドレスなNext.jsで作られていて、会員データは裏側で共通なのに、サイトを移るたびにログインし直す必要がある状態でした。
この記事では、なぜ会員を共通化したかったのか、そしてサイト間で1度のログインを引き継ぐシングルサインオン(SSO)をどう組み立てたのかを、全体像から順に説明します。関数の書き方のような細部ではなく、どんな部品がどうつながっているかが分かる形でまとめました。
会員を共通化したい理由
ブランドをまたぐユーザーの行き来
同じ会社が運営する3つのブランドを、ユーザーは必ずしも「別々のお店」として受け取っていません。片方で買った人がもう片方も見に来る、という行き来は日常的に起きます。
このときサイトを移った瞬間に「もう一度ログインしてください」と表示されると、そこで操作が止まってしまいます。すでにログイン済みの人には、そのまま買い物を続けてほしい。ブランドが分かれていても同じ会員として扱われる状態を作ること。これが共通化したかった一番の理由でした。
ポイントと会員価格を1つに保つ
裏側が同じShopifyストアである以上、ポイント残高も会員ランクも本来は1つのデータです。ところがサイトごとにログイン状態が切れていると、Aサイトで貯めたポイントがBサイトの画面に出てこない、という見え方になってしまいます。
会員価格の出し分けも同じで、ログイン状態が引き継がれて初めて正しい価格が表示されます。どのブランドを見ていても、同じ会員として同じ条件で買える。それを裏側で支えるのがSSOでした。
再ログインが購入完了率に与える影響
サイトを移るたびに再ログイン。ポイントや会員価格が引き継がれず、その場で離脱される
1度のログインで3サイトを行き来でき、会員情報もそのまま引き継がれる
図にすると、変わったのは「サイトを移るたびに入力し直す必要があるかどうか」の一点です。
再ログインにかかる時間そのものは数十秒程度ですが、その数十秒で購入をやめる人が出ます。特にスマートフォンでのメールアドレスとパスワードの入力は負担が大きく、そのまま離脱される要因になっていました。
ログイン状態が自動では共有されない理由
Cookieは発行したドメインでしか読めない
「裏側が同じなら、ログイン状態も自動的に共有されるのでは」と思われるかもしれません。ところが、そうはいかないんです。
Webのログイン状態は多くの場合Cookie(ブラウザ側に保存される小さな覚え書き)で保持されますが、Cookieには発行したドメインでしか読めないという厳格なルールがあります。brand-a.example で発行したログイン用のCookieを、brand-b.example から読み取ることはできません。裏側が同じでも、フロントのドメインが違えばログイン状態は別々に管理される。これが分断されていた直接の理由です。
サブドメインを共有する方法と、その限界
サブドメイン共有は万能ではない
すべてを同じ親ドメインの配下(例: a.example.com / b.example.com)にまとめれば、Cookieのドメイン共有だけで解決できる場合もあります。ただしブランドごとに独立したドメインを使いたい、という要件があると、この方法は選べません。
今回はブランドごとに独立したドメインを持つ方針だったため、Cookie共有という近道は最初から使えませんでした。DNS(ドメイン名と実際の配信先を結びつける仕組み)の設定でサブドメインにまとめる案も検討しましたが、ブランドごとの独立性のほうを優先しています。
移動の瞬間に証明書を手渡す
とった方法はシンプルです。Cookieが共有できないなら、サイトを移動する一瞬に「この人はログイン済み」という証明書を持たせて渡してしまう。
送り出す側のサイトが署名付きの証明書(ハンドオフトークン)を発行し、受け取った側のサイトがそれを検証して自分のセッションを作る。この受け渡しがSSOの中心になります。ログイン処理そのものをやり直すのではなく、すでに済んでいる認証の結果だけを持ち運ぶ、という考え方です。
SSO全体の流れと登場人物
ハンドオフからセッション確立まで
ユーザーはサイトAにログイン済み。セッションはサイトAのCookieに保持されている
サイトBへのリンクをクリック。リンクは専用の部品によってSSO付きに変換済み
サイトAが署名付き・短命・使い捨てのトークンを発行する
トークンを付けて、サイトBのコールバックURLへリダイレクト
サイトBがトークンの署名・有効期限・未使用を確認し、自サイトのセッションを作成
図を一言でまとめると、リンクを踏んだ一瞬のうちに、証明書の発行・受け渡し・検証が順に走っています。ユーザーの目に映るのは「リンクを踏んだらログイン済みの状態で表示された」という結果だけです。
送出側・受入側・共通設定の3つ
ハンドオフトークンを発行する
受け入れ口で検証し、セッションを作る
署名シークレット / 有効サイトリスト / 各サイトの受け入れ口URL
図が示しているのは、送出側・受入側・共通設定の3つがそろって初めてSSOが成立する、ということです。
どのサイトも送出側になり得るし、受入側にもなり得ます。だから全サイトが同じ仕組みを対称に備えている、というのが構成上の特徴。特別扱いのサイトを作らないことで、あとからサイトを増やすときにも同じ手順が使えます。
署名・短命・使い捨ての3点で守る
表が示しているのは、3つの対策がそれぞれ別の攻撃に対応している、ということです。
トークンは「本人であること」を示す一時的な許可証なので、偽造されない・古くならない・使い回されない、の3点をまとめて満たす必要があります。どれか1つが欠けると、SSOの仕組みがそのままなりすましの入口になってしまう。認証まわりは仕様の抜けが事故に直結するため、設計の各段階でAIエージェントに「この条件が抜けたら何ができてしまうか」を洗い出してもらいながら詰めていきました。
まとめ
複数ECサイト間のSSOは、「Cookieがドメインをまたげない」という制約を、署名付きトークンの受け渡しで乗り越える設計でした。要点を振り返ります。
- 会員共通化の目的:ブランドをまたぐ行き来と、ポイント・会員価格の一貫性
- 分断されていた理由:Cookieはドメインをまたげないため、ログイン状態は自動共有されない
- 解決の方法:移動の一瞬に、署名付きハンドオフトークンを受け渡す
- 安全性の担保:署名・短命・使い捨ての3点で、改ざんと再利用を防ぐ
より詳しい仕組みは、それぞれの記事で掘り下げています。トークン自体の設計は「署名付きハンドオフトークンの仕組み」で、受け取った側がどう検証してセッションを作るのかは「SSOコールバックとセッション確立のフロー」で解説します。対象サイトを増やしても破綻しない設定管理の考え方は「サイト追加に耐えるSSO設定管理」にまとめました。