# Get profile information from ID tokens
The LINE Platform issues ID tokens compliant with the OpenID Connect (opens new window) specification, allowing you to securely obtain user profile information (user ID, display name, profile picture, email address) from the LINE Platform.
If you have LINE Profile+ permission, you can also safely obtain data registered with LINE Profile+ (name, gender, birthday, phone number, address). For more information, see Get user data registered with LINE Profile+.
# Get an ID token
You can also get an ID token when you get an access token.
You can also use liff.getIDToken() to get an ID token.
# Get profile information from an ID token
Verify an ID token through one of these methods before using the information it contains:
# Use a LINE Login API endpoint
Simply by sending the ID token that you acquired with the access token and LINE Login channel ID to our dedicated API endpoint, you can verify the ID token and get the corresponding user's profile information and email address.
Example request:
curl -v -X POST 'https://api.line.me/oauth2/v2.1/verify' \
-d 'id_token=eyJraWQiOiIxNmUwNGQ0ZTU2NzgzYTc5MmRjYjQ2ODRkOD...' \
-d 'client_id=1234567890'
Example response:
{
"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"
}
For more information, see Verify ID token in the LINE Login API reference.
# Write code to validate ID tokens
You can use any JWT library (opens new window) or write your own code from scratch to validate ID tokens and obtain user profile information and email addresses.
# ID tokens
ID tokens are JSON web tokens (JWT) with information about the user. The ID token consists of a header, payload, and signature separated by period (.) characters. Each part is a base64url-encoded value. For more information, see the JWT (opens new window) specification.
# Header
These are the values included in the header.
Property | Type | Description |
---|---|---|
alg | String | ID token signature algorithm. For native apps, LINE SDK, or LIFF apps, ES256 (ECDSA using P-256 and SHA-256) is returned, and for web login, HS256 (HMAC using SHA-256) is returned. |
type | String | Payload format. JWT is returned. |
kid | String | Public key ID. Included in a header only when the value of alg is ES256 . For more information on the kid property, see the JSON Web Key (JWK) document (opens new window). For getting public key, see Get public key using kid. |
This is an example of a decoded header portion.
When alg
is HS256
:
{
"typ": "JWT",
"alg": "HS256"
}
When alg
is ES256
:
{
"typ": "JWT",
"alg": "ES256",
"kid": "a2a459aec5b65fa..."
}
# Payload
The user's information is found in the payload section.
Property | Type | Description |
---|---|---|
iss | String | https://access.line.me . URL where the ID token is generated. |
sub | String | User ID for which the ID token is generated |
aud | String | Channel ID |
exp | Number | The expiry date of the ID token in UNIX time. |
iat | Number | Time when the ID token was generated in UNIX time. |
auth_time | Number | Time when the user was authenticated in UNIX time. Not included if the max_age parameter wasn't specified in the authorization request. |
nonce | String | The nonce value specified in the authorization URL. Not included if the nonce value was not specified in the authorization request. |
amr | Array of strings | List of authentication methods used by the user. Not included in the payload under certain conditions. Includes one or more of the values below. For more information on each of these authentication methods, see User authentication.
|
name | String | User's display name. Not included if the profile scope was not specified in the authorization request. |
picture | String | User's profile image URL. Not included if the profile scope was not specified in the authorization request. |
email | String | User's email address. Not included if the email scope was not specified in the authorization request. |
This is an example of a decoded payload section.
{
"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"
}
# Signature
The signature is used to verify the validity of the response. The signature is a base64url-encoded hash computed using the HMAC SHA-256 algorithm with the base64url-encoded header + "." + payload as the value and the channel secret as a key. To ensure the security of your app, you should always verify the signature of the ID token.
# Get public key using kid
Follow these steps to get the public key using the kid
property included in the header of the decoded ID token of native apps, LINE SDK and LIFF apps:
- Check the
kid
property of the Decoded ID token header. - Access the OpenID Provider Configuration Document (opens new window) and receive a response object. For more information on properties included in the response object and their values, see OpenID Connect Discovery 1.0 (opens new window).
- The response object contains the
jwks_uri
property and its valuehttps://api.line.me/oauth2/v2.1/certs
. Access the JSON Web Key (JWK) document URL (opens new window) and receive the JSON array of JSON Web Key (JWK). For more information on JWK specifications, see JSON Web Key (JWK) (opens new window). - In the JSON array, the element that contains the
kid
property identified in step 1 is the public key.
# Decode and validate ID tokens
To decode and validate ID tokens, you can either use a JWT library or follow the instructions below.
# Use a JWT library
You can use the publicly available JWT libraries (opens new window) to decode and verify your ID tokens. The following is an example of how to decode an ID token using a library for Python®.
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')
# Decode and validate ID token
- Split the header, payload, and signature sections using the period (.) character.
- Base64-URL decode each section
- Compute the hash using the base64url-encoded header + "." + payload as the value and the channel secret as a key. Verify that the value is the same as the decoded signature.
- Confirm that the ID token was sent from LINE by checking that the value of
iss
is https://access.line.me. - Confirm that the ID token is for your channel by checking that
aud
matches your channel ID. - To confirm the validity of the ID token, confirm that the
exp
value is greater than the UNIX timestamp at the time of verification. - To prevent replay attacks, confirm that the value of
nonce
is the same as thenonce
value specified in the authorization request. Store thenonce
value with the user session. Although this step is optional, we strongly recommend including thenonce
value.
The following is an example using 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