ハコヅミを作る #51:ベータ版を始めようとしたら、「招待制」が守られていなかった

前回(#50)で、レビューで見つかったものを直し終えました。残りの準備を済ませて、ベータ版を始める日です。

  • 残りの準備:データを戻す手順と、入口を1つにすること
  • 守りを外して試したら、招待していないアカウントで入れた
  • Google の「テスト中」は、何を守っているのか
  • アプリの側に、招待の一覧を作る

残りの準備

ベータ版の前に、2つを済ませました。

データを戻す手順

データベースには、過去の時点に戻す仕組みがあります。ただ、#49 で書いたとおり、戻すと、そのあいだに退会した人のデータまで戻ってきます。

そこで、退会した人を見分ける番号と、退会した日時だけを、7 日のあいだ、データベースとは別の場所(Cloudflare の KV)に残すことにしました。データベースと同じ場所に置くと、戻したときに、この記録も一緒に戻ってしまうからです。

手順書を書いて、開発環境で、実際に戻すところまで試しました。「戻せるはず」と「戻したことがある」は、違います。

入口を1つにする

本番には、独自ドメインのほかに、Cloudflare が自動で付ける URL が2種類ありました。ログインは独自ドメインからしかできないので、残す理由がありません。設定で閉じました。

ここまでは、予定どおりです。


今までの守りと、外す順番

今までの本番は、2つの関門で守っている、と考えていました。

  1. Cloudflare Access:自分しか、URL を開けない
  2. Google のログイン:Google の設定が「テスト中」で、登録した人(テストユーザー)しかログインできない

ベータ版では、1 だけを外します。2 が、招待制の関門になります。テスタから応募が来たら、Google のテストユーザーに足す。足していない人は、Google の画面で断られる。そういう設計でした。

紹介のページにも、「今はベータ版で、招待した方だけがログインできます」と書いてあります。

手順書には、外した直後に確かめることを並べてありました。その中の1行が、これです。

テストユーザーに登録していない Google アカウントで、ログインを押すと、
Google の「アクセスをブロック」の画面になる(ログインできない)

入れてしまった

Access を外して、順に確かめました。紹介のページが開く。ログインが要る画面は、ログインの画面に移る。応答のヘッダーも付いている。

残ったのが、上の1行です。テストユーザーでない Google アカウントを、持っていませんでした。そこで、自分の2つ目のアカウントをテストユーザーから外して、試しました。

ログインできました。

最初は、前に許可した記録が Google の側に残っているのだろう、と考えました。Google のアカウントの設定から、ハコヅミとのつながりを消して、もう一度。

ログインできました。

Access を戻して、入口を閉じます。ここまで、外していたのは数十分です。どこにも知らせていないので、知らない人が登録した様子はありません。


原因を、1つずつ消す

一緒に作っている Claude Code と、原因を絞りました。

疑ったこと 確かめ方 結果
見ている Google Cloud のプロジェクトが、本番のものと違う 本番のログインが Google に渡している番号と、プロジェクトの番号を比べる 同じ
公開ステータスが「本番」になっている Google Cloud の画面 「テスト中」
試したアカウントが、プロジェクトのメンバー メンバーの一覧 入っていない

設定は、全部正しい。それでも入れる。

ここで Claude Code が、Google の公式のヘルプを読みに行きました。答えは、そこに書いてありました。

「テスト中」のアプリは、テストユーザーしか使えない。ただし、アプリが求めるのが、名前・メールアドレス・プロフィールだけのときは、例外。テストユーザーの一覧にいなくても、使える。

ハコヅミが Google に求めているのは、ちょうどこの3つだけです。つまり、ふつうの「Google でログイン」には、テストユーザーの制限は、最初から効きません。

招待制の関門は、なかったことになります。


なぜ、気づかなかったか

振り返ると、気づく機会は2回ありました。

1回目は、設計のときです。「Google のテストユーザーで、招待制にする」と決めました。Google の画面には、「テスト中の間は、テストユーザーのみがアプリにアクセスできます」と書いてあります。それを読んで、そのとおりだと思いました。例外は、別のページに書いてあります。

2回目は、#48 のレビューです。別のセッションの AI が、こう指摘していました。

「招待した人だけ」を守る仕組みが、コードにない

このとき、「守っているのは Google の設定で、コードの外にある」と答えて、直さないと決めました。指摘は、正しかったわけです。コードの外にあると思っていた守りを、誰も実物で確かめていませんでした。

助かったのは、手順書に「登録していないアカウントで、断られることを確かめる」と書いてあったことです。そして、その行を飛ばさなかったことです。別のアカウントを持っていなかったので、飛ばしたくなる行でした。


アプリの側に、招待の一覧を作る

直し方は、3つ考えました。

案 中身
A 招待した人のメールアドレスの一覧を持ち、初めてログインする人が一覧にいなければ、断る
B 招待の一覧をデータベースに持ち、管理画面から足す・外す
C 招待制をやめて、誰でも登録できるベータ版にする

A にしました。作るものが小さく、一般に公開するときに、外すだけで済みます。

一覧の置き場

最初は、サーバーの秘密の設定値に、メールアドレスを並べるつもりでした。Issue の下書きを書いている途中で、Claude Code が弱点に気づきました。秘密の設定値は、入れたあとに中身を見られません。テスタを1人足すたびに、全員分を入れ直すことになります。

代わりに、Cloudflare の KV に、1人を1つのキーで置くことにしました。ダッシュボードで、1行足す・消す・見る、ができます。メールアドレスを、ソースコードのリポジトリに入れずに済みます。

断る場所

ログインに使っている Better Auth には、ユーザーを作る直前に呼ばれる入口がありました。ここで「だめ」と返すと、ユーザーもセッションも作らずに、ログインの画面へ戻してくれます。

決めたことは、次のとおりです。

  • 確かめるのは、初めてログインする(ユーザーを作る)ときだけ。もう登録している人は、確かめない
  • 一覧にキーがない、一覧を読めない、Google が確認済みとしていないメールアドレス。どれも、断る
  • 一覧が空なら、誰も新しく登録できない

迷ったら、断る側に倒します。

ログインの画面。赤い字で「このアカウントは、招待されていません。」、その下に「ハコヅミは今はベータ版で、招待した方だけが使えます。」と「テスタに応募する」のリンク、「Google でログイン」のボタンが出ている

招待していないアカウントでログインしようとしたときの画面

退会したら、招待も消す

一覧を持つと、新しい問題が1つ出ます。プライバシーポリシーには、「退会すると、すぐに消えます」と書いてあります。退会した人のメールアドレスが、招待の一覧に残ったままでは、約束に例外が増えます。

退会のときに、招待の一覧からも消すことにしました。もう一度使うには、招待し直しです。退会の確認の画面にも、そう書きました。

消す順番は、招待の一覧を最初にします。ここで失敗したら、まだ何も消えていないので、やり直せます。招待だけ消えて、あとが失敗しても、困りません。もう登録している人は、招待を確かめないからです。


今度は、実物で確かめる

同じまちがいを、繰り返さないようにします。

自動テストは、Better Auth を実際に動かして、「一覧にいない人は、ユーザーができない」ことを確かめています。直す前のコードで流すと、ちゃんと落ちることも見ました。

ただ、それだけでは足りません。今回の原因は、「実物で確かめていなかった」ことです。開発環境に出したあと、本物の Google を通して、手で確かめました。

  1. 自分のアカウントで、退会する
  2. 招待の一覧から、自分のキーが消えているのを見る
  3. もう一度ログインする → 「このアカウントは、招待されていません。」
  4. キーを足し直す → ログインできる

本番でも、同じことを、Access を付けたまま確かめました。守りが効いているのを見てから、入口を開けます。今朝は、順番が逆でした。


おわりに

  • 外のサービスの設定に守りを任せるなら、条件に合わないもので、実際に断られることを確かめる。画面に「〜のみがアクセスできます」と書いてあっても、例外は別のページにある
  • 「守りはコードの外にある」と答えたくなったら、その守りを、誰がいつ確かめたかを思い出す
  • 確かめるのが面倒な行ほど、飛ばさない。飛ばしたくなる行に、いちばん大事なことが書いてある
  • 入口を開ける前に、守りを確かめる。開けてから確かめると、確かめているあいだ、開いている
  • 迷ったら、断る側に倒す。一覧が空なら、誰も入れない
  • 約束(退会すると消える)は、あとから足したものにも、守る

今日のうちに始めるつもりだったベータ版は、半日遅れました。それでも、テスタを招く前に見つかって、よかったと思っています。

次回は、あらためて、ベータ版を始めます。

← トップページに戻る