第2章 「ユーザー」って何? — Google認証と、いろいろなID

📖 この章のゴール:「ユーザー」とは何か、ログインで裏側に何が起きるか、そして ユーザーにまつわる “いろいろなID” の違い が分かる。第4章で出てきた user_id の正体も、ここではっきりします。 ← 目次・はじめにへもどる


📱 Twitterではこう見える

  • ログインすると、画面が「自分」になります。自分の名前・アイコン・投稿が出る。
  • 一度ログインすると、しばらく開かなくても、また開くとログインしたまま
  • パスワードを覚えていなくても、「Googleでログイン」ならスッと入れる。

あたりまえに使っていますが、ここには ①「ユーザー」という存在②それを指すID③ログイン状態の保存 という3つの仕組みがかくれています。順に見ていきます。


🤔 そもそも「ユーザー」って何?(🟢 基礎)

大事な区別から。人間のあなたと、システムが見るあなたは別物です。

システムから見た「あなた」= データベースの中の1行(1件のデータ)。 名前・メール・登録日などが入った「あなたカード」が1枚、倉庫にある、という感じです。

そして、その1行には 他と絶対にかぶらないID(背番号) が付いています。これが「あなた」を指す唯一の手がかりです。

🪪 たとえ話:会員カードの会員番号 同姓同名の人がいても、会員番号が違えば別人と分かります。名前は変わるかもしれないけれど、番号は一生変わらない。システムは名前ではなく、この番号(ID)であなたを見分けます。

Supabaseでは、この「ユーザーの1行」は auth.users という特別な表に入ります。ログインすると、そこにあなたの行が1つできます。 その行のID —— それが第4章で出てきた auth.uid()(持ち主を指すID)の正体です。


🤔 なぜ自分でパスワードを持たない方がいいの?(🟢 基礎)

「ログイン」と聞くと、パスワードを自分のアプリで預かる姿を想像するかもしれません。でも初心者がそれをやるのはとても危険です。

  • パスワードを自分のデータベースに保存する → 漏れたら大惨事(暗号化・ハッシュ化など、守りも難しい)
  • パスワードの使い回しで、他サービスの被害にもつながる

そこで 「Googleでログイン」 の出番です。

パスワードの確認を、Google に任せます。 あなたのアプリはパスワードを一切持ちません。 「この人は確かに本人ですよ」というお墨付きだけをGoogleから受け取る——これが安全で簡単な近道です。

この「外部にログイン確認を任せる仕組み」を OAuth(オーオース) と呼びます。


🛠 Supabaseでこう作る(🟢 基礎)

実際のコードはほんの数行です(GoogleをONにする管理画面の手順は付録Bにまとめます)。

① ログインを始める

// 「Googleでログイン」ボタンを押したとき
await supabase.auth.signInWithOAuth({ provider: 'google' });

1行ずつ:

  • supabase.auth.signInWithOAuth(...) … 「OAuthでログインを始めて」とSupabaseにお願い。
  • { provider: 'google' } … 相手は Google だよ、という指定。

これを実行すると Google の画面に飛び、「許可」すると戻ってきます。そのとき Supabase が auth.users にあなたの行を用意し、ログイン状態にしてくれます。

② いまログインしている自分を知る

// ログイン中のユーザーを取り出す
const { data: { user } } = await supabase.auth.getUser();
console.log(user.id);   // ← これが auth.uid()(第4章の user_id に入るID)
  • supabase.auth.getUser() … 「いまログインしてるの誰?」と尋ねる。
  • user.id … その人のID(UUID)。第4章で tweets.user_id に入っていたのは、まさにこれです。

🔎 ユーザーまわりの「いろいろなID」を整理(🟢 → 🔧)

ここがこの章のいちばん大事なところです。「ユーザーのID」と一口に言っても、実は何種類もあります。 ごちゃ混ぜにすると事故るので、整理します。

ID 何者か 変わる? 使いどころ
Google側のアカウントID(OAuthの sub Googleが各アカウントに振る、変わらないID 108…(長い数字) 変わらない Googleと結びつけるための裏方。アプリで直接は普段使わない
auth.users.id(SupabaseのユーザーUUID) あなたのアプリでの中心のID a1b2c3d4-…(UUID) 変わらない これが auth.uid()tweets.user_id もこれ
profiles の id(プロフィール表) 公開プロフィールの行。ふつう auth.users.id同じ値にする 同上 変わらない 表示名・自己紹介など「見せてよい情報」を置く
ハンドル(@name) 人が読む・打つためのID @taro 変えられる URL・@メンション。人間向けの表示ID
メールアドレス 連絡先 taro@example.com 変わりうる ログイン補助・通知。IDとして使うと変更で困る

🟢 まず押さえる2点

  1. 「機械が使うID」と「人が使うID」を分ける。
    • 機械用 = auth.users.id(UUID・変わらない・見分け専用)
    • 人間用 = @ハンドル(読みやすい・変えられる・表示専用)
  2. データの紐づけ(第4章の user_id など)は、必ず「機械用の変わらないID」で行う。
    • @ハンドルやメールで紐づけると、本人がそれを変更したとき 過去の投稿が全部 迷子になります。

💡 なぜ profiles 表を別に作るの? … auth.users はログインの根幹なので直接いじらないのが安全。そこで、表示名や自己紹介などは auth.users.id と同じIDをキーにした profilesに置き、こちらを自由に編集します。「変わらない芯のID(auth.users)」と「見せる・編集する情報(profiles)」を分ける、と覚えてください。

🔧 なぜ連番(1, 2, 3…)を避けて UUID にするのか

ユーザーのIDを 1, 2, 3…連番にすると、こんな困りごとがあります。

  1. 総当たりされる(enumeration)/users/1/users/2… と順番に叩けば、全員を機械的に巡回できてしまう。
  2. 規模がバレる … ID が 5000 なら「ユーザーは約5000人」と分かるし、次の人のIDも予測できる。
  3. URLやAPIにIDが出たとき、推測で他人の資源を試されやすい

だから「ユーザー」のような大事な対象は、UUID(a1b2c3d4-… のような長いランダム値)が定番です。Supabaseの auth.users.id も最初からUUIDです。

🤔 「推測されても良いの? ダメなの?」への答え

いい質問です。本質はこうです。 正しい守りは「IDを秘密にすること」ではなく、「権限でチェックすること」(=第4章のRLS)。 IDが他人に見えても、権限がなければ何もできないのが本物の安全です。これを 「隠すことに頼らない」(英語で security by obscurity を避ける)と言います。 ——ただし連番には上の②③の「情報がにじみ出る」問題があるので、実務では 「①IDはUUIDにする + ②アクセスは権限(RLS)で守る」の二段構えにします。 逆に、見られても実害がない対象(例:公開ツイートのID)は連番でも大きな問題はありません。「件数や次のIDを知られたくない」ときだけUUIDを選ぶ、という判断もあります。

まとめ:ユーザーIDは UUID。アクセス制御は RLS(権限)で。IDの秘匿には頼らない。


🍪 ログイン状態は「どこ」に保存される?(🟢 → 🔧)

「一度ログインすると、しばらく続く」のはなぜでしょう。ここで、DBに保存されるデータと、ブラウザに保存されるデータの違いが出てきます。

ログインに成功すると、「この人は確かにログイン済み」という証明書(トークン)が発行され、それが あなたのブラウザに保存されます。だから再読み込みしても、しばらく開かなくても、ログインが続くのです。

ブラウザ側の保存場所は、主に2種類あります。

  • クッキー(Cookie) … ブラウザがサーバーへの通信に自動で付けて送る小さなメモ。
  • localStorage(ローカルストレージ) … ブラウザの中の保管箱。自動送信はされず、プログラムが読み書きする。SupabaseのJSクライアントは、既定でこちらに証明書を置きます。

「DBに保存」と「ブラウザに保存」の違い

  データベース(サーバー側) ブラウザ側(Cookie / localStorage)
置き場所 ネットの向こうの倉庫 あなたの端末の中
誰のもの 全員共通の「正本(おおもと) その人の、そのブラウザだけ
ツイート本文・user_id ログインの証明書(トークン)・表示の設定
消えると 全員に影響 その人がログアウト状態に戻る程度

⚠️ 証明書(トークン)は「鍵」です。 盗まれると なりすまされます。 だから localStorage に置く場合は、XSS(画面に悪いスクリプトを差し込む攻撃)に注意が必要です。秘密の鍵やパスワードを、安易にブラウザへ置かない——これは第10章「ありがちな失敗」でもう一度ふれます。


⚠️ ハマりどころ

  • メールアドレスや @ハンドルでデータを紐づける … 本人が変更したら過去データが迷子に。紐づけは auth.users.id(不変のUUID)で。
  • 「ログインしている=安全」と思い込む認証(誰か)と認可(してよいか=第4章)は別物。ログイン済みでも、他人のデータに触れないよう RLS が要ります。
  • Google側のIDを主キーにしようとする … ふつうは Supabase の auth.users.id を使えば十分。GoogleのIDは Supabase が裏で結びつけてくれます。
  • トークンを自分でいじる・平文で扱う … ログインの証明書はSupabaseに任せ、手で触らない。

🤖 AIに頼むなら(Vibe codingのコツ)

🗣 プロンプト例: 「Supabaseで Googleログインを実装して。ログイン中ユーザーの取得と、profiles テーブル(主キーは auth.users.id と同じ uuidも作って。表示用の @ハンドルprofiles の別カラムにして、データの紐づけはハンドルやメールではなく auth.users.idやって」

出てきたコードのチェックポイント:

  1. 紐づけが auth.users.id(UUID)になっている?(@ハンドルやメールを主キーにしていないか)
  2. profiles の主キーが auth.users.id を参照している?
  3. ログイン状態の管理を自前で書かず、Supabaseの仕組みに任せている?

📝 ことばメモ

  • 認証(authentication):「あなたが誰か」を確かめること(←→ 認可=してよいか・第4章)
  • OAuth(オーオース):パスワードの確認を Google など外部に任せる仕組み
  • auth.users / auth.uid():Supabaseのユーザー表と、ログイン中のユーザーID(UUID)
  • UUID:ランダムで長い、重複しないID(連番の代わりに使う)
  • ハンドル(@name):人が読む・打つ表示用のID(変更できる)
  • クッキー / localStorage:ブラウザ側の保存場所
  • トークン:「ログイン済み」を示す証明書(鍵なので秘密に)

➡️ 次の章へ

「あなた」がIDで表される、ということが分かりました。次の第3章では、いよいよ ツイートを投稿します。その投稿に、この章で手に入れた auth.users.id(=持ち主のID)user_id として付く——その瞬間を作ります。

← 目次・はじめにへもどる