2026-08-10 ウォレットのずれの検知を全ページへ広げる(Issue #44)
- 課題: 署名したウォレットと操作しているウォレットのずれを検知して
POST /api/auth/logoutを呼ぶuseEffectがcomponents/SignInWithEthereum.tsxの中にあり、このコンポーネントを置いているのはapp/setup/page.tsxだけだった。そのため自動破棄が効くのは/setupを開いている間に限られ、/checkinや/applyでアカウントを切り替えてもサーバーのセッションは旧アドレスのまま、ヘッダーの表示も旧アドレスのままだった。#40 で直ったのは「再読み込みすると検知が効かなくなる」ほうで、「どのページでも効く」にはなっていなかった(PR #43 のレビューで指摘)。
権限が増える類の問題ではなかった。 残るのは本人が正当にサインインしたアドレスのセッションで、他人のセッションになるわけではない。ずれるのは表示と、本人が「今どのアカウントで操作しているか」の認識。
決定
1. アカウントのずれは SessionStatus で見る
検知を lib/useWalletSessionGuard.ts の useSignOutOnAccountChange() に切り出し、components/SessionStatus.tsx から呼ぶ。このコンポーネントだけが SiteHeader 経由でルートレイアウトに乗り、全ページに存在するため。#40 でヘッダーがセッションを知るようになったことで、置き場所として使えるようになった。
- フックは早期returnより前に呼ぶ。
SessionStatusは取得中と未サインインでnullを返すが、表示を出さない状態でも検知は動かす必要がある。 useAccount()を使うが、SessionStatusはProvidersの内側にあるので wagmi のコンテキストは足りている。クライアント側だけの追加なので、/と/setupは静的なまま(npm run buildの出力で確認)。
2. チェーンのずれは /setup でしか見ない
SignInWithEthereum に残し、条件をチェーンだけに絞る。
署名が証明しているのは「そのアドレスの持ち主であること」で、今つないでいるネットワークはその証明を無効にしない。 全ページで見ると、Polygonへの接続を前提にしない /checkin や /apply でネットワークを切り替えただけでサインアウトされる。Polygonが要る操作は /setup が案内するので、そこだけで見れば足りる。
アカウントの判定を両方に置かないのは、/setup を開いている間だけ logout が二重に飛ぶため。アカウントは SessionStatus、チェーンは SignInWithEthereum と、重ならない形に分けた。
3. 判定は画面から切り離してテストする
lib/domain/walletSession.ts の shouldDiscardSession() に比較と2つのガードを置く。vitest.config.ts はNode環境で .ts のみを対象にしており、ブラウザ依存のフローは手動検証という方針なので、フックそのものではなく判定だけを自動テストの対象にする。
固定したいのは次の2つで、どちらも「有効なセッションを誤って破棄しない」側の性質。
- ウォレット未接続では破棄しない。 wagmi の再接続が終わるまで
addressはundefinedを通る。 - チェックサム表記と小文字を揃えてから比較する。 揃えないと常に不一致になり、サインインした直後に破棄される。
4. logout + 再取得は useSignOut() へ寄せる
同じ fetch と再取得が、ヘッダーのサインアウトボタン・アカウント検知・チェーン検知の3箇所に必要になった。lib/useSession.ts の useSignOut() に寄せる。破棄に失敗しても再取得だけは行う(表示だけサインイン済みのまま残すと、押せるはずの操作が弾かれる)。
含めなかったもの
- チェーンのずれの検知を廃止すること。
/setupでの既存の挙動を変えない範囲に留めた。廃止の是非は、Polygon切替カードの扱いと合わせて別途決める - 切り替えを検知したことの画面通知。現状は黙って未サインインの表示に戻る
補足
lib/session.ts の cookieOptions に「maxAge を足さない」理由をコメントで残した。iron-session は cookieOptions に maxAge キーがあると ttl からの算出をやめるため、Cookieの寿命が SESSION_TTL_SECONDS から外れる(PR #42 のレビュー指摘)。#44 の変更とは独立だが、lib/session.ts を触るPRがしばらく無さそうだったのでここへ含めた。