GoogleアカウントのOAuthクレデンシャルを再利用して、YouTube APIを用いたアップロードツールの運用負荷を軽減する

YouTubeへの動画アップロードを自作ツールで行っている方も多いと思います。しかし、OAuthアプリを公開するには審査が必要で、個人利用のツールではその審査を通すのが現実的ではありません。一方で、非公開のOAuthアプリであればYouTube APIを利用できますが、リフレッシュトークンの有効期限が数週間に制限されており、期限が切れるたびに再認証が必要です。この仕様がツールの運用負荷を増加させる原因となっています。

本記事では、リフレッシュトークンの期限そのものを伸ばすことはできませんが、運用負荷を軽減する方法について説明します。それは、「ツールで使用するリフレッシュトークンを共通化する」です。この方法により、一度再認証すれば他のツールでは再認証が不要になります。

リフレッシュトークンを共通化する方法

ツールごとにデータストアが独立している場合、共通化が課題となります。ここではAWS S3を利用して解決します。AWS S3をデータベースのように扱うために、自作のRubyライブラリ「s3_backend _model」を使用します。
https://github.com/jiikko/s3_backend_model

モデルの実装例

以下のようにリフレッシュトークンを保存するシングルトンモデルを実装します。

class GoogleCredential < S3BackendModel::Base
  use_s3_backend bucket: 'hogehoge-bucket', prefix_key: 'google_credentials',
    s3_client: Aws::S3::Client.new(region: 'ap-northeast-1', credentials: Aws::Credentials.new(ENV.fetch('AWS_S3_ACCESS_KEY_ID'), ENV.fetch('AWS_S3_SECRET_ACCESS_KEY')))

  attr_accessor :id, :object

  def self.instance
    id = 'data.json'
    find(id) || new(id: id, s3_head_object: {})
  end

  def initialize(id:, s3_head_object:)
    @id = id
    begin
      @body = JSON.parse(fetch_body)
    rescue Aws::S3::Errors::NoSuchKey
      nil
    end
  end

  def refresh_token
    return if @body.nil?

    @body['refresh_token']
  end
end

書き込み方法

リフレッシュトークンを書き込む際は、次のコードを使用します。JSONをS3に保存する際は、content_typeを明示します。

class OmniauthCallbacksController < ApplicationController
  def google_oauth2
    if (credentials = request.env['omniauth.auth']['credentials']).present?
      GoogleCredential.instance.update(credentials.to_json, params: { content_type: 'application/json' })
    end

    redirect_to root_path, notice: 'Google OAuth2 authentication was successful.'
  end
end

これにより、リフレッシュトークンの再認証作業を1回で済ませることができ、複数ツールでの運用負荷を大幅に削減できます。

以上。