# IDトークンからプロフィール情報を取得する
LINEプラットフォームは、OpenID Connect (opens new window)仕様に準拠するIDトークンを発行しているため、LINEプラットフォームからユーザーのプロフィール情報(ユーザーID・表示名・プロフィール画像・メールアドレス)を安全に取得できます。
所定の申請等を行った法人ユーザーは、LINE Profile+に登録された情報(氏名・性別・誕生日・電話番号・住所)も取得できます。詳しくは、「LINE Profile+に登録されている情報を取得する」を参照してください。
# IDトークンを取得する
アクセストークンを取得するときに、IDトークンも取得できます。
liff.getIDToken()を利用してIDトークンを取得することもできます。
# IDトークンからプロフィール情報を取得する
IDトークンに含まれる情報を使用する前に、以下のいずれかの方法でIDトークンを検証してください。
# LINEログインAPIのエンドポイントを利用する
アクセストークンと一緒に取得したIDトークンと、LINEログインのチャネルIDをエンドポイントに送信するだけで、IDトークンを検証し、ユーザーのプロフィール情報とメールアドレスを取得できます。
リクエストの例:
curl -v -X POST 'https://api.line.me/oauth2/v2.1/verify' \
-d 'id_token=eyJraWQiOiIxNmUwNGQ0ZTU2NzgzYTc5MmRjYjQ2ODRkOD...' \
-d 'client_id=1234567890'
レスポンスの例:
{
"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",
"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)を参照してください。
# ヘッダー
ヘッダーには以下の値が含まれます。
プロパティ | タイプ | 説明 |
---|---|---|
alg | String | IDトークンの署名アルゴリズム。ネイティブアプリやLINE SDK、LIFFアプリに対してはES256 (ECDSA using P-256 and SHA-256)が、ウェブログインに対してはHS256 (HMAC using SHA-256)が返されます。 |
type | String | ペイロードの形式。JWT が返されます。 |
kid | String | 公開鍵ID。alg の値が ES256 の場合のみヘッダーに含まれます。kid プロパティについて詳しくは、『JSON Web Key (JWK)のドキュメント (opens new window)』を参照してください。公開鍵の取得方法は、「kidを使って公開鍵を取得する」を参照してください。 |
以下はデコードしたヘッダー部分の例です。
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 | IDトークンの有効期限(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トークンの署名は必ず検証する必要があります。
# kidを使って公開鍵を取得する
ネイティブアプリやLINE SDK、LIFFアプリのデコードしたIDトークンのヘッダーに含まれるkid
プロパティを使って公開鍵を取得するには、以下の手順に従います。
- デコードしたIDトークンのヘッダーの
kid
プロパティを確認します。 - 『OpenID Provider Configuration Document (opens new window)』にアクセスし、レスポンスオブジェクトを受け取ります。 レスポンスオブジェクトに含まれるプロパティとその値について詳しくは、『OpenID Connect Discovery 1.0 (opens new window)』を参照してください。
- レスポンスオブジェクトに、
jwks_uri
プロパティとその値としてhttps://api.line.me/oauth2/v2.1/certs
が含まれています。『JSON Web Key(JWK)ドキュメントURL (opens new window)』にアクセスし、JSON Web Key (JWK) のJSON配列を受け取ります。JWKの仕様について詳しくは、『JSON Web Key (JWK) (opens new window)』を参照してください。 - JSON配列の中で、手順1で確認した
kid
プロパティを含む要素が公開鍵です。
# 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