2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TwitterAPIをOAuth2.0 user contextで叩く

Last updated at Posted at 2022-04-16

はじめに

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:plainS256です。セキュリティ上S256一択です。

scope

一覧表から選んで「+」で連結します。

scope=tweet.write+tweet.read+users.read+offline.access

state

リクエストとリダイレクトの間で状態を維持するために使用するランダムな値です。リダイレクト時にそのまま帰ってきます。これを用いてどのユーザーのリダイレクトなのか判別します。

GASにはリダイレクト用の便利な関数があるのでそれを使用します。
リダイレクトを受け取る関数やリダイレクト事に追加されるパラメータを紐づけたstateを作成してくれます。
リダイレクトURLはhttps://script.google.com/macros/d/{スクリプトID}/usercallbackにする必要があります。

GAS
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_methodplainの時は、code_challengecode_verifierそのものです。
code_challenge_methodS256の時は、code_veriferSHA-256でハッシュ化してそれをbase64URLエンコードしたものがcode_challengeになります。

サンプルコードのcode_challenge_methodSHA256です

GAS
//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で作成したものです。
GAS
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:scopeoffline.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敗)

2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?