はじめに
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敗)