✉️

なぜソーシャルログインの際にemailをキーにして参照するのか

2023/12/01に公開
2

ritouです。

Digital Identity技術勉強会 #iddance Advent Calendar 2023 の 初日の記事です。

https://qiita.com/advent-calendar/2023/iddance

こちら、参加者を募集中です!気軽に参加してみてください!してくれよ!はよ!

なんの話か

ちょっと想定以上に反応をいただいたこちらの記事について、ちょっとだけ補足をしたいと思います。

https://sizu.me/ritou/posts/sb41dem2cehd

なんの話か詳しく

自分のはてブのコメントをつけたポストにもたくさん反応いただきました。

https://twitter.com/ritou/status/1725663684297626098

実際、海外のサービスはメアドをキーにして参照してるところも多く

これはサービスのDBのUserテーブルがemailをプライマリキーにしているという話ではありません(が、そう思われた方からDMが来ました)。

最初にパスワード認証やメールでリンクを送信して認証させる仕組みを実装している状態から、ソーシャルログインを実装しようとする際に "email" をキーにした参照をすることがあるんよ、と言う話です。

そして、先ほどのポストの続きに、MediumやTwitterも同じようなことやってるぞと書きました。
今回の件ではcatnoseさんもNotionを参考にされたようなことをXのポストに書かれていました。

そこで、このあたりの実際の挙動を紹介しようかと思いましたが、なんと2022/03にZennで関連する記事を書いてました(完全に記憶がない)。

https://zenn.dev/ritou/articles/b25ad4d3c4f59f

この記事を書いたきっかけはログイン画面などに出てくる「Googleのこのユーザーでログインしていかんか?」っていう仕組みを調べていたときに気になったからです。

ID連携においてメアドをキーにした既存ユーザーとの連携は、メアドが普遍の値ではないことからアンチパターンとも言われていますが、その辺りを真面目にやろうと思うとステップが増えてしまう、みたいなジレンマもあるところです。

この時は「気持ちはわからんでもない」みたいな書き方をしています。

真面目にやろうと思うとステップが増えてしまう

この投稿ではこの部分、なぜこうなってしまうのか について触れます。

なぜこうなってしまうのか

サービスのUserテーブルがemailをプライマリキーにしているわけではない

何十年もやってるサービスならまだしも、現代のアプリケーション開発においてはさすがにUserテーブルにプライマリーキーとしてのidというものがあるでしょう。

emailも同じテーブルもしくは別の管理で、ユニーク制約はあるでしょうけれども、Userテーブルのプライマリーキーにはなっていないのがほとんどだと思います。

ソーシャルログイン実装におけるあるべき姿

Qiitaでソーシャルログイン実装してみました記事 では

  • パスワード認証のときはemailで参照してパスワード比較するよな
  • ソーシャルログインでも同じでヨシ!

みたいなノリが感じられる実装が見られた(スクール関連で教えられたのか?)ので度々コメントしていたものですが、さすがに最近はそういう記事は減りました。

一般的には、

  • アカウント設定 みたいなページで Googleアカウントと連携 という機能を提供し、連携したら Google から受け取ったユーザーIDと自サービスのユーザーIDの紐付けを管理する
  • ソーシャルログイン ではGoogle から受け取ったユーザーIDと自サービスのユーザーIDの紐付けがあった場合にログインさせる

と言うのがソーシャルログインの ミニマム実装 となります。

その上で、紐付けがなかったときや新規登録に使う場合もメールアドレスが既存ユーザーと同じだったら同じ人ではないか?うまく紐づけられたら「アカウントの分裂」みたいなことが防げるのではないか?という、追加の検討をしていくことになります。

この辺の話はこの記事に書いています。

https://zenn.dev/ritou/articles/50366b09381e8d

で、こうやって地道に段階的に設計をしてエラーになるケースを考えて...という地味な作業をしたり、ある程度汎用的なところまで実装しているライブラリ/フレームワーク/プロダクト/サービスを使う必要があります。

"設定"ページから連携しないと使えないのマ?

上記のようなID連携のプラクティスを意識せずに、とにかくシンプルにソーシャルログインを組み込もうと思った時によくあるのが 「連携しないとログインに使えないのめんどくさくない?」 というものです。

パスキーの場合、一度登録しないと使えません。

パスワードも設定しないとログインには使えません。

しかし、ソーシャルログインの場合、IdPからもらったメールアドレスを使ったらこの"ログイン状態からの設定"がワンチャン不要では と考えてしまうのです。

同じemailのユーザーでは連携なしにログイン = emailをキーに参照してログインの誕生

メアドで参照する場合、設定ページからの連携が不要にできます。 なんて言われたら、勘所のある開発者でなければ「シンプルでいいね、採用」となりそうですし、どっちかのメアドが変わったらログインできなくなったとしても、他の認証方式があるならええか ぐらいであれば許容されたりする結果、現状のようになっているのでしょう。

ログインできなくなるぐらいならピンとこなくても、リサイクルされた時に初めて「他のアカウントにログインできる」みたいな怖い話が出てくるわけです。しかし、それでも 「メールでパスワードリセットできるサービスだってリサイクルされたら終わりだろ。それと変わらん」 みたいな考えでスルーされたりします。

こうして、メアドをキーにして参照する仕組みが爆誕してしまうのです。

最近のX

上述の調査段階では現X(当時のTwitter)は最初にUserIDの紐付けの方を見ていた気がしましたが、最近試した時はメアドしか見てないようでした。

設定あたりを見ると、こんなんなりますけどね、

実はこの連携を解除したところで、Googleログインしたらメアドで参照してログイン成功してまた連携済みになるんですよ。当然ながらここから連携する機能もないです。メアドで参照してるから要らないのです。こんなんでいいのでしょうか

終わり

今回は なぜソーシャルログインの際にemailをキーにして紐づけてしまうのか をまとめてみました。
こんな記事を書いても、同じような実装するサービスが今後も出てくるでしょうし、メールアドレスの変更なんてせずに普通に使っている人にとってはシンプルな方がいいやろと思われる方もいるでしょう。しかし、元記事に書いたように "ユーザー自身の連携" 機能を端折ることで無視できない小さい落とし穴が生まれるんだということだけは覚えておきましょう。

明日は会社の方のアドカレを書く予定です(かきました)

https://zenn.dev/mixi/articles/1b8e6cf89f609a

ではまた。

Discussion

asip2k25asip2k25

X(旧Twitter)では、次のような実装になっている気がします。
(実際にどのような実装になっているのかはわかりません。)

未連携のソーシャルログインでは、Google etcから受け取ったemailをキーにして
ユーザーテーブルを参照し、既に同じメールアドレスのレコードがある場合、
そのレコードにGoogle etcから受け取った(ユーザー)IDを紐付け、連携済みにし、
ログインする。
連携済みのソーシャルログインでは、Google etcから受け取った(ユーザー)IDを
キーに、ユーザーテーブルを参照し、ログインしている。

(ログイン時にキーとするIDとは別に、(Google etcから受け取った)emailを
画面表示用に(ユーザーテーブルに)保持しているので、emailをキーにして
紐づけているようにみえてしまっているだけのような気がします。)

このような実装であれば、初回連携時のみ emailをキーにして参照し、それ以降は
(Google etcから受け取った(ユーザー))IDをキーにして参照するので、問題ない
のではないでしょうか?

ritouritou

コメントありがとうございます。

初回連携時のみ emailをキーにして参照し、それ以降は(Google etcから受け取った(ユーザー))IDをキーにして参照

以前挙動を調査した際はこうなっていました。

最近はより最適化されたようで、メアド変更時にはID連携が解消されるようになっています。
これは「ID連携済みかつemailが異なる状態が存在しない」ということを示しています。
Google側でメアドを変更した際にどうなるかという検証が困難なので想像の域を超えませんが、現在はemailのみで参照しているように思えます。

初回連携時のみ emailをキーにして参照

初回のみでも良くないという話をしています。