GoogleのAPIを使って、何かしらデータを取得したいとき。

たとえば、ユーザーがYouTubeに投稿した動画の統計情報を取得したい、なんてときが該当します。

OAuth認証を実行してユーザーから許可をもらい、取得したアクセストークンを設定してAPIを実行することになりますがこのアクセストークンには期限があります。

アクセストークンは有効期限が1時間と短めに設定されていて、期限が切れたらOAuthでユーザーから認可を得るための画面を表示させて、再度ユーザーから許可をもらわないといけません。

1時間ごとにユーザーから許可もらうのはユーザーとしても運営としても面倒だし嫌ですね。

しかし、リフレッシュトークンを使うと、この問題を解消することができます。

順を追って説明していきます。

YouTubeの場合のサンプルプログラムは以下に掲載されています。

Using OAuth 2.0 for Web Server Applications

とりあえず、こちらにもサンプルを転記。

require 'google/apis/youtube_analytics_v1'
require 'google/api_client/client_secrets'
require 'json'
require 'sinatra'

enable :sessions
set :session_secret, 'setme'

get '/' do
  unless session.has_key?(:credentials)
    redirect to('/oauth2callback')
  end
  client_opts = JSON.parse(session[:credentials])
  auth_client = Signet::OAuth2::Client.new(client_opts)
  youtube = Google::Apis::YoutubeAnalyticsV1::YouTubeAnalyticsService.new
  report = youtube.query_report('channel==MINE', '2016-05-01', '2016-06-30', 'views', options: { authorization: auth_client })
  
  "<pre>#{JSON.pretty_generate(report.to_h)}</pre>"
end

get '/oauth2callback' do
  client_secrets = Google::APIClient::ClientSecrets.load
  auth_client = client_secrets.to_authorization
  auth_client.update!(
    :scope => 'https://www.googleapis.com/auth/yt-analytics.readonly',
    :redirect_uri => url('/oauth2callback'))
  if request['code'] == nil
    auth_uri = auth_client.authorization_uri.to_s
    redirect to(auth_uri)
  else
    auth_client.code = request['code']
    auth_client.fetch_access_token!
    auth_client.client_secret = nil
    session[:credentials] = auth_client.to_json
    redirect to('/')
  end
end

リフレッシュトークンを使おう

アクセストークンは1時間しかもちませんが、回避方法があります。

リフレッシュトークンを使うと、ユーザーに改めて許可をもらうことなく、アクセストークンを再取得することが可能です。

このリフレッシュトークンは最初にアクセストークンを取得したときに一緒についてきます。

上記のサンプルコードはリフレッシュトークンを使うように書かれていないので、少し手を加えてリフレッシュトークンを使えるようにしてみましょう。

まず、get '/oauth2callback'の初期化のところです。

以下のようにauth_client.update!の引数に'access_type' => 'offline'と設定しておきます。

こうすることで、アクセストークンを再取得するときにユーザーから許可を得なくても大丈夫になります。

client_secrets = Google::APIClient::ClientSecrets.load
auth_client = client_secrets.to_authorization

# additional_parametersのオプションを追加しておく
auth_client.update!(
  :scope => 'https://www.googleapis.com/auth/yt-analytics.readonly',
  :redirect_uri => url('/oauth2callback'),
  :additional_parameters => {
    'access_type' => 'offline' # offline accessを許容するように設定しておく
  }
)

次にリフレッシュトークンを使うコードを足し込んでいきます。

get '/'でYouTubeのAPIを実行していますが、APIを実行する前にauth_clientにAPIのクライアントシークレットを設定し、refresh!メソッドを実行します。

このメソッドを実行した時点でリフレッシュトークンを使って、アクセストークンを再取得してくれます。

これにより、アクセストークンの期限が切れてもアクセストークンが更新されて再びAPIを実行することができます。

get '/' do
  unless session.has_key?(:credentials)
    redirect to('/oauth2callback')
  end
  client_opts = JSON.parse(session[:credentials])
  auth_client = Signet::OAuth2::Client.new(client_opts)

  # ここでclient_secretを設定しておく
  auth_client.client_secret = ENV['YOURE_CLIENT_SECRET']
  # これでrefresh_tokenを使って、access_tokenを再取得する
  auth_client.refresh!
  
  # そうすれば、APIを再び実行することができる
  youtube = Google::Apis::YoutubeAnalyticsV1::YouTubeAnalyticsService.new
  report = youtube.query_report('channel==MINE', '2016-05-01', '2016-06-30', 'views', options: { authorization: auth_client })
  
  "<pre>#{JSON.pretty_generate(report.to_h)}</pre>"
end

このrefresh!メソッドは以下のソースコードにあるように、fetch_access_token!の別名として定義されているだけですね。

fetch_access_token!を使っても、リフレッシュトークンは使ってくれると思います。

refresh!メソッドのソースコード

この記事の環境情報

  • Ruby 3.1.2
  • googleauth 0.17.1