# ウェブアプリにLINEログインを組み込む
このページでは、OpenID Connect (opens new window)プロトコルをサポートし、ユーザー情報をIDトークンで取得できるLINEログインをウェブアプリに組み込む方法を説明します。 LINEログインを組み込めるアプリがない場合は、サンプルアプリを利用できます。「LINEログインを始めよう」を参照してください。
- ウェブアプリにLINEログイン v2.0を組み込む場合は、「ウェブアプリにLINEログインを組み込む(LINEログイン v2.0)」を参照してください。
- LINE SDKが提供されている環境では、LINE SDKを使用してLINEログインを組み込んでください。ネイティブアプリにLINEログインを組み込むために、このページで説明している仕組みを利用しないでください。LINE SDKを組み込む方法については、「ネイティブアプリにLINEログインを組み込む」を参照してください。
# ログインのフロー
ウェブアプリ向けのLINEログインの処理(ウェブログイン)は、OAuth 2.0の認可コード付与のフロー (opens new window)とOpenID Connect (opens new window)プロトコルに基づいています。 ウェブログインのフローの概要は以下のとおりです。 フロー図で「Web app」が関係しているフローは、ウェブアプリで実装が必要です。
# チャネルを作成する
「LINEログインチャネル」を作成し、ウェブアプリ用に設定します。
# コールバックURLを設定する
コールバックURLは、ユーザーが認証と認可の操作を行ったあとで、ウェブアプリが認可コードとstate
を受け取るために使用されます。
LINE Developersコンソールのチャネル設定の[LINEログイン設定]タブで、コールバックURLを設定してください。 1つのチャネルに、複数のコールバックURLを指定できます。
# メールアドレスの取得権限を申請する
LINEログイン v2.1を使用する場合は、LINEログインを使ってログインしたユーザーのメールアドレスを取得できます。
ウェブアプリでユーザーのメールアドレスを取得する場合は、あらかじめ、LINE Developersコンソールからメールアドレス取得権限を申請してください。
[チャネル基本設定]タブの[OpenID Connect]で、 [申請]をクリックします。
申請条件に同意して、メールアドレスの取得と利用についてユーザーに提示する文面のスクリーンショットをアップロードします。
申請が受理されると[メールアドレス取得権限]に「申請済み」と表示されます。
# ユーザーに認証と認可を要求する
LINEプラットフォームとユーザーの間で、認証と認可のプロセスを開始させます。 ユーザーがLINEログインボタンをクリックしたときに、以下の例のように認可URLに必須のクエリパラメータを付けてユーザーをリダイレクトしてください。
https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=1234567890&redirect_uri=https%3A%2F%2Fexample.com%2Fauth&state=12345abcde&scope=profile%20openid&nonce=09876xyz
認可URLに付与できるクエリパラメータは、以下のとおりです。
パラメータ | タイプ | 必須 | 説明 |
---|---|---|---|
response_type | String | 必須 | code |
client_id | String | 必須 | LINEログインチャネルのチャネルID。LINE Developersコンソールで確認できます。 |
redirect_uri | String | 必須 | LINE Developersコンソールに登録したコールバックURL |
state | String | 必須 | クロスサイトリクエストフォージェリ (opens new window)防止用の固有な英数字の文字列。 ログインセッションごとにウェブアプリでランダムに生成してください。 なお、URLエンコードされた文字列は使用できません。 |
scope | String | 必須 | ユーザーに付与を依頼する権限。詳しくは、「スコープ」を参照してください。 |
nonce | String | 任意 | リプレイアタック (opens new window)を防止するための文字列。この値はレスポンスで返されるIDトークンに含まれます。 |
prompt | String | 任意 | consent 。ユーザーが要求された権限をすべて付与済みであっても、強制的に同意画面を表示します。 |
max_age | Number | 任意 | ユーザー認証後に許容される最大経過時間(秒)。OpenID Connect Core 1.0 (opens new window)の「Authentication Request」のセクションで定義されているmax_age パラメータに相当します。 |
ui_locales | String | 任意 | LINEログインで表示される画面の表示言語および文字種。RFC 5646(BCP 47) (opens new window)で定義されている言語タグを、優先順位が高い順に、スペース区切りのリストで設定します。OpenID Connect Core 1.0 (opens new window)の「Authentication Request」のセクションで定義されているui_locales パラメータに相当します。 |
bot_prompt | String | 任意 | LINE公式アカウントを友だち追加するオプションをユーザーのログイン時に表示します。normal またはaggressive を指定します。詳しくは、「LINEログインしたときにLINE公式アカウントを友だち追加する(ボットリンク)」を参照してください。 |
- ウェブアプリにLINEログインボタンを追加する際は、「LINEログインボタン デザインガイドライン」に従ってください。
- LINEログインボタンを表示せず、認可URLに直接リンクすることもできます。
- ユーザーの認証情報は、ウェブアプリには通知されません。
LIFFブラウザ内でLINEログインによる認可リクエストを行う際の動作は保証されません。また、LIFFアプリを外部ブラウザで開く場合には、LINEログインによる認可リクエストではなく、liff.login()を利用してください。
# スコープ
scope
パラメータに指定できるスコープは以下のとおりです。複数のスコープを指定するには、URLエンコードされた空白文字(%20)で区切って指定します。
スコープ | プロフィール情報 | IDトークン (ユーザーIDを含む) | IDトークン内の 表示名 | IDトークン内の プロフィール画像のURL | IDトークン内の メールアドレス |
---|---|---|---|---|---|
profile | ✓ | - | - | - | - |
profile%20openid | ✓ | ✓ | ✓ | ✓ | - |
profile%20openid%20email | ✓ | ✓ | ✓ | ✓ | ✓(※) |
openid | - | ✓ | - | - | - |
openid%20email | - | ✓ | - | - | ✓(※) |
※email
を指定してユーザーにメールアドレスの取得権限を要求するには、あらかじめメールアドレス取得権限を申請してください。
- LINE公式アカウントとユーザーの友だち関係を取得するには、
profile
のスコープを持つアクセストークンが必要です。 - プロフィールやメールアドレスの取得権限のほかに、さらに追加で権限を利用したい場合は、担当営業までご連絡いただくか、弊社パートナー (opens new window)にお問い合わせください。
# ユーザーがユーザー認証を行う
LINEログインを組み込むウェブアプリ側で、認証の機能を実装する必要はありません。
認可URLにリダイレクトされたユーザーは、以下のいずれかの認証方法でログインできます。
認証方法 | 説明 |
---|---|
自動ログイン | ユーザーの操作なしでログイン。LINEログイン画面や確認画面は表示されません |
メールアドレスログイン | LINEログイン画面にメールアドレスとパスワードを入力してログイン |
QRコードログイン | LINEログイン画面に表示されたQRコードを、スマートフォン版LINEのQRコードリーダーでスキャンしてログイン |
シングルサインオン(SSO)によるログイン | 「次のアカウントでログイン」と表示された確認画面でログインボタンをクリックしてログイン |
自動ログインとSSOが両方利用できる環境ではSSOの方が優先して動作します。詳しくは、FAQの「LINEログインで「次のアカウントでログイン」という画面が表示されました。これは自動ログインに失敗していますか。」を参照してください。
ログインするとLINE公式アカウントからログイン通知が送信されます。ログイン通知についてはヘルプの「LINE公式アカウントからログイン通知が届いた (opens new window)」や「[◯◯で◯◯にログインしました]というトークが届いた (opens new window)」を参照してください。
ユーザーが選択した認証方法は、IDトークンで確認できます。IDトークンについては、「アクセストークンを取得する」の「レスポンス」を参照してください。
# 自動ログイン
ユーザーの操作なしでログインできます。LINEログイン画面や確認画面は表示されません。
自動ログインは、スマートフォン版LINEにログインしている状態で、以下のブラウザで認可URLにアクセスした場合に、自動的に行われます。
- LINE内ブラウザ
- 初めてLINEログインをする外部ブラウザ
自動ログインが利用可能な環境について詳しくは、FAQの「自動ログインについて教えてください。」を参照してください。
# メールアドレスログイン、QRコードログイン
ユーザーは以下のいずれかの認証方法でログインできます。
- メールアドレスログイン
- QRコードログイン(PC版LINEでのみ表示されます)
これらのログイン方法は、スマートフォン版LINEにログインしていない状態で、外部ブラウザで認可URLを初めて開いた場合に使用できます。
# シングルサインオン(SSO)によるログイン
ユーザーはログインボタンをクリックするだけでログインできます。
SSOは、過去にLINEログインをしたことがある外部ブラウザで認可URLにアクセスした場合に使用できます。
一度ウェブアプリからLINEログインをすると access.line.me
というドメイン名でCookieが保存されます。以降もそのCookieが有効な限り、同じブラウザでログインする際にSSOの画面が表示されます。
# ユーザーが認可を行う
LINEログインを組み込むウェブアプリ側で、認可の機能を実装する必要はありません。
開発者がscope
パラメータで指定した情報へのアクセス権を、ユーザーが認可します。
なお、ユーザーは権限の付与に同意せずにウェブアプリにアクセスする場合があります。認可URLで指定した権限の付与を、ユーザーに拒否される可能性も考慮してウェブアプリを開発してください。
同意画面の例:
scope
パラメータで指定した権限がprofile
またはopenid
の場合は、ユーザーが既に権限を付与していると同意画面は表示されません。- 権限に
email
が含まれる場合は、メールアドレスが変わらない限り、ユーザーが同意してから一定の期間は同意画面が表示されません。
# ウェブアプリで認可コードまたはエラーレスポンスを受け取る
ユーザーによる認証と認可のプロセスが終了すると、ユーザーはコールバックURLにリダイレクトされます。
ユーザーがアプリにアクセス権を付与したときは、認可コードが渡されます。 また、アクセス権の付与を拒否したときは、エラーレスポンスが渡されます。
# 認可コードを受け取る
ユーザーの認証と認可が完了すると、以下のクエリパラメータを含むコールバックURLにリダイレクトされます。
パラメータ | タイプ | 説明 |
---|---|---|
code | String | アクセストークンの取得に使用される認可コード。有効期間は10分です。また、認可コードは1回のみ利用可能です。 |
state | String | クロスサイトリクエストフォージェリ (opens new window)防止用の固有な英数字の文字列。この値が認可URLに付与したstate パラメータの値と一致することを検証してください。 |
friendship_status_changed | Boolean | チャネルにリンクされているLINE公式アカウントとユーザーの関係が、ログイン時に変わった場合はtrue です。それ以外はfalse です。注意:このパラメータは、ユーザーに認証と認可を要求するときに bot_prompt クエリパラメータを指定し、かつ、ユーザーがログインしたときにLINE公式アカウントを友だち追加するオプションが表示された場合にのみ返されます。詳しくは、「LINEログインしたときにLINE公式アカウントを友だち追加する(ボットリンク)」を参照してください。 |
リダイレクト先URLの例:
https://example.com/callback?code=abcd1234&state=0987poi&friendship_status_changed=true
# エラーレスポンスを受け取る
アプリの要求する権限の付与をユーザーが拒否した場合、以下のクエリパラメータを含むコールバックURLにリダイレクトされます。
パラメータ | タイプ | 必須 | 説明 |
---|---|---|---|
error | String | 必須 | エラーコード |
error_description | String | 任意 | エラーの内容 |
state | String | 任意 | 認可URLに含めたstate パラメータ。この値で、どのプロセスが拒否されたか特定できます。 |
リダイレクト先URLの例:
https://example.com/callback?error=access_denied&error_description=The+resource+owner+denied+the+request.&state=0987poi
# ウェブアプリでアクセストークンを取得する
LINEプラットフォームから認可コードを受け取った際、同時に受け取ったstate
パラメータと、認証と認可を要求したときに指定したstate
パラメータが一致すれば、アクセストークンを取得できます。
リクエストの例:
curl -v -X POST https://api.line.me/oauth2/v2.1/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=authorization_code' \
-d 'code=xxx' \
-d 'redirect_uri=xxx' \
-d 'client_id=xxx' \
-d 'client_secret=xxx'
# レスポンス
LINEプラットフォームがアプリからのリクエストを検証し、以下の表に示すアクセストークンなどのデータをアプリに返します。
LINEログイン機能に追加または変更があったときに、レスポンスやIDトークンのJSONオブジェクトの構造が変更される場合があります。この変更には、プロパティの追加、順序の変更、データの要素間の空白や改行の有無、データ長の変化が含まれます。将来、従来と異なる構造のペイロードを受信しても不具合が発生しないように、サーバーを実装してください。
プロパティ | タイプ | 説明 |
---|---|---|
access_token | String | アクセストークン。有効期間は30日です。 |
expires_in | Number | アクセストークンの有効期限が切れるまでの秒数。 |
id_token | String | ユーザー情報を含むJSONウェブトークン(JWT) (opens new window)。このプロパティは、スコープにopenid を指定した場合にのみ返されます。詳しくは、「IDトークンからプロフィール情報とメールアドレスを取得する」を参照してください。 |
refresh_token | String | 新しいアクセストークンを取得するためのトークン。アクセストークンが発行されてから最長90日間有効です。 |
scope | String | ユーザーが付与する権限。ただし、email スコープは権限が付与されていてもscope プロパティの値としては返されません。 |
token_type | String | Bearer |
以下は、JSONレスポンスの例です。
{
"access_token": "bNl4YEFPI/hjFWhTqexp4MuEw5YPs...",
"expires_in": 2592000,
"id_token": "eyJhbGciOiJIUzI1NiJ9...",
"refresh_token": "Aa1FdeggRhTnPNNpxr8p",
"scope": "profile",
"token_type": "Bearer"
}
詳しくは、『LINEログイン v2.1 APIリファレンス』の「アクセストークンを発行する」を参照してください。
# IDトークンからプロフィール情報を取得する
LINEプラットフォームは、OpenID Connect (opens new window)仕様に準拠するIDトークンを発行しているため、LINEプラットフォームからユーザーのプロフィール情報(ユーザーID・表示名・プロフィール画像・メールアドレス)を安全に取得できます。
所定の申請等を行った法人ユーザーは、LINE Profile+に登録された情報(氏名・性別・誕生日・電話番号・住所)も取得できます。詳しくは、「LINE Profile+に登録されている情報を取得する」を参照してください。
IDトークンに含まれる情報を使用する前に、以下のいずれかの方法でIDトークンを検証してください。
# LINEログインAPIのエンドポイントを利用する
アクセストークンと一緒に取得したIDトークンと、LINEログインのチャネルIDをエンドポイントに送信するだけで、IDトークンを検証し、ユーザーのプロフィール情報とメールアドレスを取得できます。
リクエストの例:
curl -v -X POST 'https://api.line.me/oauth2/v2.1/verify' \
-d 'id_token=eyJraWQiOiIxNmUwNGQ0ZTU2NzgzYTc5MmRjYjQ2ODRkOD...&client_id=1234567890'
レスポンスの例:
{
"iss": "https://access.line.me",
"sub": "U1234567890abcdef1234567890abcdef",
"aud": "1234567890",
"exp": 1504169092,
"iat": 1504263657,
"nonce": "0987654asdf",
"amr": [
"pwd",
"linesso",
"lineqr"
],
"name": "Taro Line",
"picture": "https://sample_line.me/aBcdefg123456",
"email": "taro.line@example.com"
}
詳しくは、『LINEログイン v2.1 APIリファレンス』の「IDトークンを検証する」を参照してください。
# IDトークンを検証するコードを書く
任意のJWTライブラリ (opens new window)を使ったり、独自のコードを書いたりして、IDトークンを検証し、ユーザーのプロフィール情報とメールアドレスを取得できます。
# IDトークン
IDトークンは、ユーザー情報を含むJSONウェブトークン(JWT)です。IDトークンは、ピリオド(.)で区切られたヘッダー、ペイロード、および署名から構成されます。各部分はbase64urlでエンコードされています。詳しくは、JWTの仕様 (opens new window)を参照してください。
# ヘッダー
以下はデコードしたヘッダー値の例です。LINEログインでは、HS256(HMAC using SHA-256)またはES256(ECDSA using P-256 and SHA-256)が使用されます。kid
はalg
がES256
の場合のみ返されます。
alg
がHS256
の場合:
{
"typ": "JWT",
"alg": "HS256"
}
alg
がES256
の場合:
{
"typ": "JWT",
"alg": "ES256",
"kid": "a2a459aec5b65fa..."
}
# ペイロード
ユーザー情報はペイロード部分に含まれます。
プロパティ | タイプ | 説明 |
---|---|---|
iss | String | https://access.line.me 。IDトークンの生成URLです。 |
sub | String | IDトークンの対象ユーザーID |
aud | String | チャネルID |
exp | Number | トークンの有効期限(UNIXタイム) |
iat | Number | IDトークンの生成時間(UNIXタイム) |
auth_time | Number | ユーザー認証時間(UNIXタイム)。認可リクエストにmax_age の値を指定しなかった場合は含まれません。 |
nonce | String | 認可URLに指定したnonce の値。認可リクエストにnonce の値を指定しなかった場合は含まれません。 |
amr | Stringの配列 | ユーザーが使用した認証方法のリスト。以下のいずれかの値が含まれます。それぞれの認証方法については「ユーザーがユーザー認証を行う」を参照してください。
|
name | String | ユーザーの表示名。認可リクエストにprofile スコープを指定しなかった場合は含まれません。 |
picture | String | ユーザープロフィールの画像URL。認可リクエストにprofile スコープを指定しなかった場合は含まれません。 |
email | String | ユーザーのメールアドレス。認可リクエストにemail スコープを指定しなかった場合は含まれません。 |
以下はデコードしたペイロード部分の例です。
{
"iss": "https://access.line.me",
"sub": "U1234567890abcdef1234567890abcdef ",
"aud": "1234567890",
"exp": 1504169092,
"iat": 1504263657,
"nonce": "0987654asdf",
"amr": ["pwd"],
"name": "Taro Line",
"picture": "https://sample_line.me/aBcdefg123456"
}
# 署名
署名を使ってレスポンスの有効性を検証します。Base64urlでエンコードされているヘッダー、ピリオド、およびペイロードを繋げた文字列を値とし、チャネルシークレットを鍵として、HMAC SHA-256アルゴリズムでハッシュ化した値をbase64urlでエンコードしたのが署名です。アプリのセキュリティを保つため、トークンの署名は必ず検証する必要があります。
# IDトークンをデコードして検証する
IDトークンをデコードして検証するには、任意のJWTライブラリを使うか、 以下の手順に従います。
# JWTライブラリを使う
一般利用が可能なJWTライブラリ (opens new window)を使って、IDトークンをデコードして検証できます。以下はPython®向けライブラリを使ってIDトークンをデコードする例です。
import jwt
decoded_id_token = jwt.decode(id_token,
channel_secret,
audience=channel_id,
issuer='https://access.line.me',
algorithms=['HS256'])
# check nonce (Optional. But strongly recommended)
nonce = '_stored_in_session_'
expected_nonce = decoded_id_token.get('nonce')
if nonce != decoded_id_token.get('nonce'):
raise RuntimeError('invalid nonce')
# IDトークンをデコードして検証する
- ピリオド(.)を区切り文字として、ヘッダー、ペイロード、および署名を分割します。
- 各部分をbase64urlでデコードします。
- Base64urlでエンコードされたヘッダー、ピリオド、およびペイロードを繋げた文字列を値とし、チャネルシークレットを鍵として、ハッシュ値を算出します。この値がデコードした署名と同じであるかどうかを検証します。
iss
の値がhttps://access.line.meであり、IDトークンがLINEから送信されたものであることを確認します。aud
の値がお使いのチャネルIDと一致しており、IDトークンがお使いのチャネルを対象としていることを確認します。- IDトークンの有効性を確認するには、
exp
の値が検証時より後のUNIXタイムスタンプであることを確認します。 - リプレイアタックを防止するため、
nonce
の値が認可リクエストに指定したnonce
の値と等しいことを確認します。nonce
の値をユーザーセッションと共に保存します。このステップは省略できますが、nonce
の値を含めることを強くお勧めします。
以下はPython 3を使った例です。
import base64
import hashlib
import hmac
import json
import time
def base64url_decode(target):
rem = len(target) % 4
if rem > 0:
target += '=' * (4 - rem)
return base64.urlsafe_b64decode(target)
def check_signature(key, target, signature):
calc_signature = hmac.new(
key.encode('utf-8'),
target.encode('utf-8'),
hashlib.sha256
).digest()
return hmac.compare_digest(signature, calc_signature)
def decode_id_token(id_token, channel_id, channel_secret, nonce=None):
# step 1
header, payload, signature = id_token.split('.')
# step 2
header_decoded = base64url_decode(header)
payload_decoded = base64url_decode(payload)
signature_decoded = base64url_decode(signature)
# step 3
valid_signature = check_signature(channel_secret,
header + '.' + payload,
signature_decoded)
if not valid_signature:
raise RuntimeError('invalid signature')
payload_json = json.loads(payload_decoded.decode('utf-8'))
# step 4
if payload_json.get('iss') != 'https://access.line.me':
raise RuntimeError('invalid iss')
# step 5
if payload_json.get('aud') != channel_id:
raise RuntimeError('invalid aud')
# step 6
if int(time.time()) > payload_json.get('exp'):
raise RuntimeError('invalid exp')
# step 7 (Optional. But strongly recommended)
if nonce is not None:
if payload_json.get('nonce') != nonce:
raise RuntimeError('invalid nonce')
return payload_json
# 次のステップ
取得したアクセストークンを使って、以下の操作を行えます。