GoogleAppsScript + Twitterで、OAuthConfigからOAuth2のApplication-only authenticationへと移行した

GoogleAppsScriptを使ってTwitter APIを叩いていたものがあったのですが、7/7に動作しなかったことがあったため、原因と対応した時のメモを残します。

 

経緯

6月中旬にGoogleよりこんな感じのメールが来ていました。

件名:対応のお願い: ご使用の Google Apps アカウントの Apps スクリプトで、廃止された OAuthConfig プロトコルが使われています - 移行が必要です

本文:
管理者の皆様

OAuth1 は 2012 年にサポートを終了し、2015 年 4 月に無効になりました。OAuthConfig for Apps Script は、2015 年 3 月 4 日にお知らせしたとおり、サポートを終了しました。ご使用の Google Apps ドメインでは、クラス OAuthConfig を介して OAuth1 呼び出しがまだ行われているようなので、ご連絡いたしました。

2015 年 7 月 6 日をもって OAuthConfig は無効になるため、ユーザーにはエラーが表示されることが予想されます。サービスの中断を避けるために、できるだけ早く以下の対応を取ることを強くおすすめします。

ドメインの Apps スクリプトのオーナーおよびユーザーに、OAuthConfig(Apps スクリプト アプリケーションの OAuthConfig API で使用)が 2015 年 7 月 6 日以降は動作しなくなることを連絡してください。

正常な動作を維持するには、Apps スクリプトのオーナーはこちらの移行手順に沿って、最新のオープン ソース ライブラリに移行する必要があります。 

 
特に問題ないだろうと放置していたところ、7/7に動かないTwitterアプリがありました。デバッグ実行をしてみたところ、

スクリプトでサポートが終了した OAuthConfig を使用しています。詳しくは http://goo.gl/IwCSaV をご覧ください。

というエラーメッセージが出て、動作しませんでした。

 
そこで調べてみたところ、以下の記事の通り、2015/7/6に機能がシャットダウンされていました。
Changes to OAuth in Apps Script - Google Apps Developer Blog

 
また、マイグレーションガイドによれば、今までと同様にOAuth1系を使おうとすると、自分で実装するか、Google製のライブラリを使えば良さそうでした。
Migrating from OAuthConfig to the OAuth1 library | Apps Script | Google Developers

 
一方、そもそもOAuth1版のTwitter APIが必要なのかと思い調べてみたところ、OAuth2版(Application-only authentication)のTwitter APIがあり、こちらでも十分なことが分かりました。
Application-only authentication | Twitter Developers

 
ただ、OAuth2版にもGoogle製のライブラリがあったものの、ソースコードを読んでみたところ、リダイレクトURLの指定があるなど、Twitter API向けのものではなさそうでした。
googlesamples/apps-script-oauth2

 
そこで、以下を参考に、Application-only authentication用のコードを自分で実装することにしました。
TwitterのApplication-only authenticationを試してみた - (゚∀゚)ktkr!

 

悩んだところ

Consumer KeyとConsumer Secret のURIエンコード方法

GoogleAppsScriptで用意されている、Utilities.base64EncodeWebSafe()を使うことにしました。
Class Utilities - base64EncodeWebSafe(data) | Apps Script | Google Developers

 

JSONのパース

今まで使っていたUtilities.jsonParseは既に廃止されていたため、以下のガイドラインに従いJSON.parseを使うことにしました。

 

Twitter のアプリ登録のCallback URLについて

Application-only authenticationでは、今までとは異なりCallback URLの設定が不要でした。

 

実装コード

以上を踏まえて実装したのが以下のコードです。

Consumer KeyとConsumer Secretを変更した上で、以下のコードをWebアプリケーションとして公開することで、動作を確認できます。

TWITTER_CONSUMER_KEY = '<your key>';
TWITTER_CONSUMER_SECRET = '<your secret>';

function doGet(e) {
  // アクセストークンの取得
  var tokenUrl = "https://api.twitter.com/oauth2/token";
  var tokenCredential = Utilities.base64EncodeWebSafe(TWITTER_CONSUMER_KEY + ":" + TWITTER_CONSUMER_SECRET);
  var tokenOptions = {
    headers : {
      Authorization: "Basic " + tokenCredential,
      "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" 
    },
    method: "post",
    payload: "grant_type=client_credentials"
  };
  var responseToken = UrlFetchApp.fetch(tokenUrl, tokenOptions);
  var parsedToken = JSON.parse(responseToken);
  var token = parsedToken.access_token;
  
  
  // Application-only authenticationでTwitter APIの利用
  var apiUrl = "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterjp&count=2";
  var apiOptions = {
    headers : {
      Authorization: 'Bearer ' + token
    },
    "method" : "get"
  };
  var responseApi = UrlFetchApp.fetch(apiUrl, apiOptions);
  
  
  // バリデーション
  if (responseApi.getResponseCode() !== 200) return "";
  var tweets = JSON.parse(responseApi.getContentText());
  if (!tweets) return "";
  
  
  // 結果を表示
  var result = "";
  for (var i = 0; i < tweets.length; i++) {
    var tweet = tweets[i].text;
    var date = new Date(tweets[i].created_at);
    result += "[" + date.toUTCString() + "]" + tweet + " / ";
  }
  return ContentService.createTextOutput(result);  
}

 
GitHub上にもソースコードを上げておきました。
thinkAmi-sandbox/GAS-TwitterOAuth2-sample