はじめに
本記事で分かること
- Sorceryを使っても、LINEログインからユーザーのメールアドレスを取得できない理由
- LINEログインのフロー
- LINEログインからメールアドレスを取得するために必要なこと
結論
LINEログインでユーザーのメールアドレスを取得するには、IDトークンの検証が必要。この検証処理がSorceryに含まれていないので、LINEログインからメールアドレスを取得することができない。
現在はSorceryはメンテナンスが行われていないため、Sorceryの使用には注意してください
対象
- Sorceryを使ってLINEログインを実装しようとされている方
環境
- Sorcery v0.17.0
- LINEログイン v2.1
- Ruby on Rails v7.1
目次
-
LINEログインのフロー
1-1. LINEログインの全体像
1-2. LINEログインからユーザーのメールアドレスを取得する方法 -
SorceryはどのようにLINEログイン処理を行うか
2-1. Sorceryの前提知識
2-2. Sorceryのソースコードを読んでみる
2-3. @user_hashの中身を見てみる
2-4. IDトークンを手動でLINEログインに送り、検証してみる -
SorceryはIDトークンを検証してくれるのか?
(補足) IDトークンを手動でLINEログインに送り、検証してみる - まとめ
- 参考資料
1. LINEログインのフロー
1-1. LINEログインの全体像
(転載:https://developers.line.biz/ja/docs/line-login/integrate-line-login/#login-flow)
上図に沿って、一つずつ解説します。
ここでのポイントは、「手順10(下方)でアクセストークンと共に、IDトークンもLINE PlatformからWebアプリに送られること」 です。
- 【A. ユーザー】LINEログインを開始する
- 【B. Webアプリ】ユーザーをLINE Platformの認可URLにリダイレクトする
- このURLパラメータには、
redirect_uri
とstate
を含める-
redirect_uri
:認証・認可完了後に、ユーザーがリダイレクトされるWebアプリのURL -
state
:CSRFを防ぐためのランダムな文字列
-
- このURLパラメータには、
- 【C. LINE Platform】LINEログイン画面をユーザーに表示する
- 【A. ユーザー】認証する(LINEにログインする)
- 【C. LINE Platform】認可画面をユーザーに表示する
- 【A. ユーザー】認可する
- 【C. LINE Platform】ユーザーを、
redirect_uri
にリダイレクトする。その際、下記2つの情報がredirect_uri
のパラメータに付加される-
state
:手順2でLINE PlatformがWebアプリから受け取ったもの -
authorization code
:ユーザーが認可された際に作られるコード。Webアプリはこれを用いて、LINE Platformからアクセストークンを取得する。
-
- 【B. Webアプリ】手順2でLINE Platformに送った
state
と、手順7でLINE Platformから受け取ったstate
が同一であるか検証する - 【B. Webアプリ】LINE Platformに、
authorization code
を送り、アクセストークンをリクエストする - 【C. LINE Platform】
authorization code
を検証し、Webアプリにアクセストークンを送る- 図には載っていませんが、この時にアクセストークンと共にIDトークンも送られます。
- 【B. Webアプリ】アクセストークンを使い、LINE Platformにユーザー情報をリクエストする
- 【C. LINE Platform】アクセストークンを検証し、Webアプリにユーザー情報を送る
1-2. LINEログインからユーザーのメールアドレスを取得する方法
まず、ユーザーのメールアドレスを取得するためには、以下の3つの準備が必要です。
先ほどのログインフローでは、アクセストークンをLINE Platformに送ると、ユーザー情報が取得できるとあります。しかし、ユーザーのメールアドレスは、これでは取得できません。IDトークンの検証によってはじめて取得できる点に注意してください。
では、Sorceryが③IDトークンの検証を行ってくれるのか、見ていきましょう(①取得権限の申請、②scope
パラメーターにemail
を指定はできている前提とします)。
2. SorceryはどのようにLINEログイン処理を行うか
2-1. Sorceryの前提知識
Sorceryのインストール方法など、基本的な使い方はこちらを参照してください
Sorceryの外部認証機能(external)については、こちらをご覧ください
2-2. Sorceryのソースコードを読んでみる
SorceryのExternalのソースコードを見てみます。
すると、アクセストークンを使い、user
情報を取得するメソッドがあります。
def sorcery_fetch_user_hash(provider_name)
provider = sorcery_get_provider provider_name
if @provider.nil? || @provider != provider
@provider = provider
@access_token = nil
@user_hash = nil
end
@access_token ||= @provider.process_callback(params, session) # sends request to oauth agent to get the token
@user_hash ||= @provider.get_user_hash(@access_token) # uses the token to send another request to the oauth agent requesting user info
nil
end
しかし、先ほど確認した通り、メールアドレスの取得には、アクセストークンではなくIDトークンの検証が必要です。
sorcery_fetch_user_hash(provider_name)
では、あくまでアクセストークンを使ったユーザー情報の取得を行っているにすぎません。
では、念のため、そこで取得された@user_hash
の中身を見てみましょう。
2-3. @user_hash
の中身を見てみる
前提として、開発中のRailsアプリに、Externalのドキュメント通りにログイン機能を実装しています。
また、else
内の初めにbinding.pry
を設置し、処理を止めています。
def callback
provider = params[:provider]
if @user = login_from(provider)
redirect_to root_path, :notice => "Logged in from #{provider.titleize}!"
else
begin
binding.pry # ここでデバッグをします
@user = create_from(provider)
reset_session
auto_login(@user)
redirect_to root_path, :notice => "Logged in from #{provider.titleize}!"
rescue
redirect_to root_path, :alert => "Failed to login from #{provider.titleize}!"
end
end
end
なお、デバッグした時点で、既にlogin_from(provider)
が実行されています。そこには、sorcery_fetch_user_hash
が含まれるので、これも実行済みです(下記ソースコードをご参照ください)。
def login_from(provider_name, should_remember = false)
sorcery_fetch_user_hash provider_name
...
では、コンソール上で@user_hash
の中身を見てみます。
@user_hash
=> {:token=>
"hoge",
:refresh_token=>"fuga",
:expires_at=>1727252560,
:expires_in=>1727252560,
:user_info=>
{"userId"=>"aaa",
"displayName"=>"山田太郎",
"pictureUrl"=>
"https://profile.line-scdn.net/xxx"},
:uid=>"aaa"}
※個人情報が含まれるため、一部値を変更しています。
やはり、@user_hash
にはメールアドレスが入っていませんでした。
2-4. IDトークンを手動でLINEログインに送り、検証してみる
1-1. LINEログインの全体像にて、アクセストークンと共に、IDトークンも送られると説明しました。
そのIDトークンは受け取れているのでしょうか?
同じ個所でbinding.pry
で処理を止めたまま、access_token
を確認してみます。
access_token
=> #<OAuth2::AccessToken:xxx
...
@params=
{"token_type"=>"Bearer",
"scope"=>"profile openid",
"id_token"=> # ここにIDトークンがある
"fuga",
"token_url"=>"https://api.line.me/oauth2/v2.1/token"},
...
すると、IDトークンは、アクセストークンと共に取得できているのが分かります。
3. SorceryはIDトークンを検証してくれるのか?
では、Sorcery(External)は、そのIDトークンを検証する処理を含むのでしょうか。
答えはNOです(少なくとも私は、externalのソースコードを読み解いても、IDトークンを検証する処理は、見つかりませんでした・・・)
(補足) IDトークンを手動でLINEログインに送り、検証してみる
なお、curlコマンドを使い、手動でIDトークンをLINE Platformに送り検証すると、メールアドレスが取得できることが確認できました。このことから、LINE Platform側には問題がないことが分かります。
# curlコマンドでIDトークンを検証してみる
curl -v -X POST 'https://api.line.me/oauth2/v2.1/verify' \
-d 'id_token=fuga' \
-d 'client_id=xxx'
# メールアドレスが返ってきた
{"iss":"https://access.line.me",(省略),"name":"山田太郎","email":"taro@gmail.com"}
4. まとめ
- LINEログインからメールアドレスを取得するには、IDトークンの検証が必要
- SorceryにはIDトークンの検証処理は含まれていない
- したがって、Sorceryを使うだけではLINEからユーザーのメールアドレスを取得できない。別途自分で処理を実装するなどして、工夫が必要
5. 参考資料