rails RailsでFirebaseのJWTtokenを利用してユーザー認証する

本稿について

本稿はサイト運営者が学んだことなどを記したメモの内容です。
全てが正確な情報とは限りません。ご注意ください。また修正するべき点は適時修正していきます

各種APIのtoken認証でFirebsaeのJWTを利用する。

before_action :confirm_token

class Token

def self.decode_firebase_token(token)
    options = {
      algorithm: 'RS256',
      iss:      "https://securetoken.google.com/project-id",
      verify_iss: true,
      aud:        "project-id", # 各々の環境で
      verify_aud: true,
      verify_iat: true,
    }
    payload, _ = JWT.decode(token, nil, true, options) do |header|
      cert = fetch_certificates[header['kid']]
      if cert.present?
        OpenSSL::X509::Certificate.new(cert).public_key
      else
        nil
      end
    end

    payload
  end

  private

  def self.fetch_certificates
    cached = Rails.cache.read(CERTS_CACHE_KEY)
    return cached if cached.present?

    res = Net::HTTP.get_response(URI(CERTS_URI))
    raise 'Fetch certificates error' unless res.is_a?(Net::HTTPSuccess)

    body = JSON.parse(res.body)
    expires_at = Time.zone.parse(res.header['expires'])
    Rails.cache.write(CERTS_CACHE_KEY, body, expires_in: expires_at - Time.current)

    body
  end
end

これをActionController::APIで実行できるようにした

class ApiController < ActionController::API
  include ActionController::HttpAuthentication::Token::ControllerMethods
  rescue_from StandardError, with: :render_error

  # login用
  def authenticate_user
    authenticate_or_request_with_http_token do |token, options|
      @user = User.find_by_token(token) if token
      if @user.present?
        session[:user_token] = token
        render 'login', formats: 'json', handlers: 'jbuilder'
      end
    end
  end

  # ユーザーのtoken確認
  def confirm_token
    authenticate_or_request_with_http_token do |token, options|
        payload = Token.decode_firebase_token(token)
        @user = User.find_by_uid(payload['user_id'])
        return true if @user.present?
    end
  end

decodeに成功すると以下のようなデータが取得できる

[4] pry(main)> Token.decode_firebase_token(token)
{"name"=>"田中 太郎",
"picture"=>
  "https://lh3.googleusercontent.com/a-/AOh14Gjur08Fo658PaLa7ayODJjhp2wlxuTJTnhB5IRE=s96-c",
"iss"=>"https://securetoken.google.com/test-application",
"aud"=>"test-application",
"auth_time"=>1602738540,
"user_id"=>"zQf3Rjnlg9eGGNhCjy9faEkHFKC3",
"sub"=>"zQf3Rjnlg9eGGNhCjy9faEkHFKC3",
"iat"=>1602738541,
"exp"=>1602742141,
"email"=>"[email protected]",
"email_verified"=>true,
"firebase"=>
  {"identities"=>
    {"google.com"=>["107844820690293321413"],
    "email"=>["[email protected]"]},
  "sign_in_provider"=>"google.com"}}
=> {"name"=>"田中 太郎",
"picture"=>"https://lh3.googleusercontent.com/a-/AOh14Gjur08Fo658PaLa7ayODJjhp2wlxuTJTnhB5IRE=s96-c",
"iss"=>"https://securetoken.google.com/dev-friendly",
"aud"=>"test-application",
"auth_time"=>1602738540,
"user_id"=>"zQf3Rjnlg9eGGNhCjy9faEkHFKC3",
"sub"=>"zQf3Rjnlg9eGGNhCjy9faEkHFKC3",
"iat"=>1602738541,
"exp"=>1602742141,
"email"=>"[email protected]",
"email_verified"=>true,
"firebase"=>{"identities"=>{"google.com"=>["107844820690293321413"], "email"=>["[email protected]"]}, "sign_in_provider"=>"google.com"}}

[参考]
https://satococoa.hatenablog.com/entry/2018/10/05/210933
Back