はじめに
TwitterAPIのOAuth2.0 user contextはTwitterAPIv2.0しか使えないデメリットがありますが、Essentialレベルでも使えるのは大きなメリットです。
client_idやclient_secretの取得は既に出来ている前提です。
を参考にしました。
サンプルコードはGASです。フルスクラッチです。
アクセストークンの取得手順
1.ユーザーに踏ませる認可URLを作成する
2.リダイレクトのパラメータを用いてアクセストークンを取得する
以上です。
ユーザーに踏ませる認可URLを作成する
TwitterのOAuth2の認可URLはhttps://twitter.com/i/oauth2/authorize です。これにクエリーパラメータを付け足していきます。
パラメータは以下の7つです。
-
response_type: 必ずcodeにしなければなりません client_id-
redirect_uri: 事前に設定したものと同じ出なければなりません -
scope:後述 -
state:後述 -
code_chellange:後述 -
code_chellange_method:plainかS256です。セキュリティ上S256一択です。
scope
一覧表から選んで「+」で連結します。
scope=tweet.write+tweet.read+users.read+offline.access
state
リクエストとリダイレクトの間で状態を維持するために使用するランダムな値です。リダイレクト時にそのまま帰ってきます。これを用いてどのユーザーのリダイレクトなのか判別します。
GASにはリダイレクト用の便利な関数があるのでそれを使用します。
リダイレクトを受け取る関数やリダイレクト事に追加されるパラメータを紐づけたstateを作成してくれます。
リダイレクトURLはhttps://script.google.com/macros/d/{スクリプトID}/usercallbackにする必要があります。
const state = ScriptApp.newStateToken()
//リダイレクトを受け取る関数名
.withMethod("authCallBack")
.withTimeout(3600)
//リダイレクト時のパラメータの追加
.withArgument("key", value)
.createToken();
code_challenge
code_challengeを作成するにはまずcode_verifierを作成します。特にcode_verifierに作成方法の指定はありません。手順2でcode_veiriferを再度使用するのでstateと紐づけて保存しておく必要があります。
そのcode_verifierを用いてcode_challengeを算出します。
code_challenge_methodがplainの時は、code_challengeはcode_verifierそのものです。
code_challenge_methodがS256の時は、code_veriferをSHA-256でハッシュ化してそれをbase64URLエンコードしたものがcode_challengeになります。
サンプルコードのcode_challenge_methodはSHA256です
//a-zまでのランダム*32文字
const code_verifier=Array(32).fill(0).map(()=>String.fromCharCode(Math.random()*26+97)).join("")
const hashed=
Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256,code_verifier,Utilities.Charset.US_ASCII)
const challenge=Utilities.base64EncodeWebSafe(hashed).replace(/=/g,"")
//パディングの「=」が消えないので、自分で消す
//stateとcode_verifierを紐づけて保存する。state作成時のwithArgumentを使用するのもアリです。
ScriptProperties.setProperty(state,code_verifier)
これでパーツは全部揃ったのでURLエンコードして組み立てます。視認性向上のため改行が入っています。
https://twitter.com/i/oauth2/authorize?
response_type=code&
client_id=client_id&
redirect_uri=https%3A%2F%2F...&
scope=tweet.write+tweet.read+users.read+offline.access&
state=abcdefg&
code_challenge=aiueo&
code_challenge_method=S256
リダイレクトのパラメータを用いてアクセストークンを取得する
リダイレクト時に付いてくるパラメータは以下の2つです。
code-
state:手順1で作成したものが帰ってきます。
stateを用いてどのユーザーのリダイレクなのかを判別して、そのユーザー用に発行したcode_veriferと、パラメータのcodeを用いてアクセストークンを取得します。
トークン取得エンドポイントはhttps://api.twitter.com/2/oauth2/tokenです。
必要パラメータは以下の5つです。
-
grant_type:必ずauthorization_codeにしなければならない -
code:受け取った物をそのまま返します。 -
redirect_uri:事前に設定したリダイレクトURLと同じでなければなりません client_id-
code_verifier:手順1で作成したものです。
function authCallBack(e){
const {code,state}=e.parameter
const options={
method:"post",
contentType:"application/x-www-form-urlencoded",
//confidential clientの場合必須。client_id、client_secretはurlエンコード推奨です。長いので省略しました
headers:{Authorization: "Basic "+Utilities.base64Encode(client_id+":"+client_secret)},
payload:{
grant_type:"authorization_code",
code:code,
redirect_uri:redirect_uri,
client_id:client_id,
code_verifier:ScriptProperties.getProperty(state)
}
}
const response=UrlFetchApp.fetch("https://api.twitter.com/2/oauth2/token",options)
}
レスポンスはJSONで帰ってきます。
{
"token_type": "bearer",
"access_token": "MEf...",
"refresh_token": "bWZ...",
"expires_in": 7200,
"scope": "tweet.write tweet.read users.read offline.access"
}
-
token_type:基本常にbearerです。bearerであることを確認してください。 -
access_token:アクセストークンです。使用方法は後述します。 -
refresh_token:scopeにoffline.accessがあれば帰ってきます。有効期限を更新出来ます。使用方法は後述します。 -
expires_in:有効期限(秒)です。 -
scope:手順2で作成したscopeが帰ってきます。
アクセストークンとリフレッシュトークンは環境変数に保存しておきましょう。
TwitterAPIを叩く
OAuth1と違い結構簡単です。ヘッダーにBearer認証を追加するだけです。
const options={
method:"post",
headers:{Authorization:"Bearer "+access_token},
contentType:"application/json",
payload:JSON.stringify({
text:"あ"
})
}
const response=UrlFetchApp.fetch("https://api.twitter.com/2/tweets",options)
{"id":1515156578613317635, "text":"あ"}
トークンをリフレッシュする
このままだと2時間でトークンが失効するので定期的にリフレッシュする必要があります。スコープにoffline.accessを入れるのを忘れないで下さい。
const options={
method:"post",
headers:{
//作成方法はトークン取得時のと同じなので割愛
Authorization:"Basic "+basic
},
contentType:"application/x-www-form-urlencoded",
payload:{
grant_type:"refresh_token",
refresh_token:refresh_token
}
}
const response=UrlFetchApp.fetch(`https://api.twitter.com/2/oauth2/token`,options)
レスポンスのJSON構造はトークン取得時のと全く同じです。
終わりに
途中でエラーが出たらUrlFetchApp.getRequestでリクエスト内容を見ることが出来るので確認してみてください。大体2回URLエンコードしてるとかです(2敗)