第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点
- 「機械が使うID」と「人が使うID」を分ける。
- 機械用 =
auth.users.id(UUID・変わらない・見分け専用) - 人間用 =
@ハンドル(読みやすい・変えられる・表示専用)
- 機械用 =
- データの紐づけ(第4章の
user_idなど)は、必ず「機械用の変わらないID」で行う。- @ハンドルやメールで紐づけると、本人がそれを変更したとき 過去の投稿が全部 迷子になります。
💡 なぜ
profiles表を別に作るの? …auth.usersはログインの根幹なので直接いじらないのが安全。そこで、表示名や自己紹介などはauth.users.idと同じIDをキーにしたprofiles表に置き、こちらを自由に編集します。「変わらない芯のID(auth.users)」と「見せる・編集する情報(profiles)」を分ける、と覚えてください。
🔧 なぜ連番(1, 2, 3…)を避けて UUID にするのか
ユーザーのIDを 1, 2, 3… の連番にすると、こんな困りごとがあります。
- 総当たりされる(enumeration) …
/users/1、/users/2… と順番に叩けば、全員を機械的に巡回できてしまう。 - 規模がバレる … ID が
5000なら「ユーザーは約5000人」と分かるし、次の人のIDも予測できる。 - 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でやって」
出てきたコードのチェックポイント:
- 紐づけが
auth.users.id(UUID)になっている?(@ハンドルやメールを主キーにしていないか) profilesの主キーがauth.users.idを参照している?- ログイン状態の管理を自前で書かず、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 として付く——その瞬間を作ります。