ひびきの技術メモ帳

駆け出しエンジニアのメモ帳

liff.getIDToken()で取得したIDTokenを使ってRailsサーバーでユーザー情報を取得するメモ

LIFF用の初期設定

application.html.slimにLIFF用のCDNを埋めると勝手に最新版を使ってくれるらしくさらに設定がこれだけで済むから楽。

doctype html
html
  head
    title
      | LiffIdTokenSample
    script charset="utf-8" src="https://static.line-scdn.net/liff/edge/2/sdk.js"
    = csrf_meta_tags
    = csp_meta_tag
    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
  body
    = yield

config/environments/developmentのhosts設定を無くしてます。理由は開発環境にngrokを使っててurlが結構頻繁に変わるからです。

Rails.application.configure do
  config.hosts.clear
end

View(楽したいからslimを使ってます)

h1
  |Profile
button#getProfile
  |getProfile
p#iss
  |iss:
p#sub
  |sub:
P#aud
  |aud:
p#exp
  |exp:
p#iat
  |iat:
p#authTime
  |auth_time:
p#nonce
  |nonce:
p#amr
  |amr:
p#name
  |name:
p#picture
  |picture:
p#email
  |email:

JavaScript

window.onload = function(){
    const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
    const getProfileButton = document.querySelector("#getProfile")
    const iss_field = document.querySelector("#iss")
    const sub_field = document.querySelector("#sub")
    const aud_field = document.querySelector("#aud")
    const exp_field = document.querySelector("#exp")
    const iat_field = document.querySelector("#iat")
    const authTime_field = document.querySelector("#authTime")
    const nonce_field = document.querySelector("#nonce")
    const amr_field = document.querySelector("#amr")
    const name_field = document.querySelector("#name")
    const picture_field = document.querySelector("#picture")
    const email_field = document.querySelector("#email")
    liff.init({
      liffId: "自分のliffIDを入れてね"
    })
    .then(() => {
      if (!liff.isLoggedIn()) {
        liff.login();
      }
    })
    .catch((err) => {
      console.log(err.code, err.message);
    });

    getProfileButton.addEventListener('click', () => {
      let idToken = liff.getIDToken()
      let body =`idToken=${idToken}`
      let request = new Request('/users', {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
          'X-CSRF-Token': token
        },
        method: 'POST',
        body: body
      });
      fetch(request)
      .then(response => response.json())
        .then(data => {
           console.log(data)
           iss_field.append(data.iss)
           sub_field.append(data.sub)
           aud_field.append(data.aud)
           exp_field.append(data.exp)
           iat_field.append(data.iat)
           authTime_field.append(data.auth_time)
           nonce_field.append(data.nonce)
           amr_field.append(data.amr)
           name_field.append(data.name)
           picture_field.append(data.picture)
           email_field.append(data.email)
          })

    })
  }

なんかごちゃごちゃ書いてありますが大方表示用のやつなので今回主に大事なとこはこれだけです。

let idToken = liff.getIDToken()
let body =`idToken=${idToken}`
let request = new Request('/users', {
headers: {
  'Content-Type': 'application/x-www-form-urlencoded;   charset=utf-8',
  'X-CSRF-Token': token
  },
  method: 'POST',
  body: body
});

fetch(request)

liff.getIDToken()で取得したIDTokenをfetchメソッドを使ってRailsに渡してます。

Controller

class UsersController < ApplicationController
  require 'net/http'
  require 'uri'
  def create
    idToken = params[:idToken]
    channelId = '自分のチャンネルIDを入れてね'
    res = Net::HTTP.post_form(URI.parse('https://api.line.me/oauth2/v2.1/verify'),
                          {'id_token'=>idToken, 'client_id'=>channelId})
    render :json => res.body
  end
end

JSからfetchで渡したIDTokenをLINEにPOST通信でHTTPリクエストを投げてユーザー情報をもらって表示のためにフロントに返します。

IDTokenを検証するためのHTTPリクエス

LINEにIDTokenを投げる時のHTTPリクエストのbody にはid_tokenclient_id(Channel IDです)の2個を最低限持たせる必要があるようです。あと任意でnonceとかuser_idを持たせられるようです。

post_form

RailsからHTTPリクエストを送るのにpost_formってやつが簡単そうだったので使ってみました。

Railsサーバー側で取得したユーザー情報をフロントで表示する。

fetch(request)
  .then(response => response.json())
  .then(data => {
    console.log(data)
    iss_field.append(data.iss)
    sub_field.append(data.sub)
    aud_field.append(data.aud)
    exp_field.append(data.exp)
    iat_field.append(data.iat)
    authTime_field.append(data.auth_time)
    nonce_field.append(data.nonce)
    amr_field.append(data.amr)
    name_field.append(data.name)
    picture_field.append(data.picture)
    email_field.append(data.email)
  })

この辺でやってるやつです。Railsから渡したjsonの情報を表示してるだけです。

参考文献

RubyのHTTPリクエストをできるだけシンプルに実装する - Qiita library net/http (Ruby 3.0.0 リファレンスマニュアル) LINEログイン v2.1 APIリファレンス | LINE Developers 参考になりましたありがとうございました

最後に

解釈が間違っているところやここは違うやり方に変えた方がいいよなどありましたらお願いします。