Skip to content

Commit

Permalink
Merge pull request #253 from yskkin/id-token-verify
Browse files Browse the repository at this point in the history
Add ID token verification endpoint
  • Loading branch information
zenizh authored May 30, 2022
2 parents 8760add + 174c98f commit 8b5c015
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
47 changes: 47 additions & 0 deletions lib/line/bot/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,40 @@ def revoke_channel_access_token_jwt(access_token)
post(oauth_endpoint, endpoint_path, payload, headers)
end

# Verify ID token
#
# @param id_token [String] ID token
# @param nonce [String] Expected nonce value. Use the nonce value provided in the authorization request. Omit if the nonce value was not specified in the authorization request.
# @param user_id [String] Expected user ID.
#
# @return [Net::HTTPResponse]
def verify_id_token(id_token, nonce: nil, user_id: nil)
channel_id_required

endpoint_path = '/oauth2/v2.1/verify'
payload = URI.encode_www_form({
client_id: channel_id,
id_token: id_token,
nonce: nonce,
user_id: user_id
}.compact)
headers = { 'Content-Type' => 'application/x-www-form-urlencoded' }
post(oauth_endpoint, endpoint_path, payload, headers)
end

# Verify access token v2.1
#
# @param access_token [String] access token
#
# @return [Net::HTTPResponse]
def verify_access_token(access_token)
payload = URI.encode_www_form(
access_token: access_token
)
endpoint_path = "/oauth2/v2.1/verify?#{payload}"
get(oauth_endpoint, endpoint_path)
end

# Get all valid channel access token key IDs v2.1
#
# @param jwt [String]
Expand All @@ -161,6 +195,19 @@ def get_channel_access_token_key_ids_jwt(jwt)
get(oauth_endpoint, endpoint_path, headers)
end

# Get user profile by access token
#
# @param access_token [String] access token
#
# @return [Net::HTTPResponse]
def get_profile_by_access_token(access_token)
headers = {
"Authorization" => "Bearer #{access_token}",
}
endpoint_path = "/v2/profile"
get(oauth_endpoint, endpoint_path, headers)
end

# Push messages to a user using user_id.
#
# @param user_id [String] User Id
Expand Down
69 changes: 69 additions & 0 deletions spec/line/bot/client_channel_token_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,38 @@
}
EOS

VERIFY_ID_TOKEN_CONTENT = <<"EOS"
{
"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"
}
EOS

VERIFY_ACCESS_TOKEN_CONTENT = <<"EOS"
{
"scope": "profile",
"client_id": "1440057261",
"expires_in": 2591659
}
EOS

PROFILE_BY_ACCESS_TOKEN_CONTENT = <<"EOS"
{
"userId": "U4af4980629...",
"displayName": "Brown",
"pictureUrl": "https://profile.line-scdn.net/abcdefghijklmn",
"statusMessage": "Hello, LINE!"
}
EOS

describe Line::Bot::Client do
def dummy_config
{
Expand Down Expand Up @@ -112,4 +144,41 @@ def generate_client

expect(response).to be_a(Net::HTTPOK)
end

it 'verifies ID token' do
uri_template = Addressable::Template.new Line::Bot::API::DEFAULT_OAUTH_ENDPOINT + '/oauth2/v2.1/verify'
stub_request(:post, uri_template)
.with(body: { client_id: 'channel id', id_token: 'dummy_id_token', nonce: 'dummy_nonce'})
.to_return { |request| {body: VERIFY_ID_TOKEN_CONTENT, status: 200} }

client = generate_client

response = client.verify_id_token('dummy_id_token', nonce: 'dummy_nonce')

expect(response).to be_a(Net::HTTPOK).and(have_attributes(body: VERIFY_ID_TOKEN_CONTENT))
end

it 'verifies access token' do
uri_template = Addressable::Template.new Line::Bot::API::DEFAULT_OAUTH_ENDPOINT + '/oauth2/v2.1/verify?access_token=dummy_access_token'
stub_request(:get, uri_template).to_return { |request| {body: VERIFY_ACCESS_TOKEN_CONTENT, status: 200} }

client = generate_client

response = client.verify_access_token('dummy_access_token')

expect(response).to be_a(Net::HTTPOK).and(have_attributes(body: VERIFY_ACCESS_TOKEN_CONTENT))
end

it 'gets profile by access token' do
uri_template = Addressable::Template.new Line::Bot::API::DEFAULT_OAUTH_ENDPOINT + '/v2/profile'
stub_request(:get, uri_template)
.with(headers: { 'Authorization' => 'Bearer dummy_access_token'})
.to_return { |request| {body: PROFILE_BY_ACCESS_TOKEN_CONTENT, status: 200} }

client = generate_client

response = client.get_profile_by_access_token('dummy_access_token')

expect(response).to be_a(Net::HTTPOK).and(have_attributes(body: PROFILE_BY_ACCESS_TOKEN_CONTENT))
end
end

0 comments on commit 8b5c015

Please sign in to comment.