年末年始から Twitter OAuth 1.0a の仕様を調べていていました。
Deno の Twitter 向けライブラリは、開発者自身のアクセストークンを使うライブラリはちらほら見つかります。
ユーザーのアクセストークンを取得する、OAuth 1.0a の Using 3-legged OAuth
用の公開されたライブラリは見当たらなかったので、自前で作って公開しました。
(OAuth 2.0 用は、あった。OAuth2 Client for Deno)
参考にしたもの含めメモしておきます。
公開したライブラリ
2022年1月11日公開 Deno 向けで、Twitter API の中で 認証部分だけフォーカスしたライブラリ。
任意のAPIの利用は既にライブラリが割とあるので、認証部分だけ特にtwitterログインを作りたかったので作った。
deno.land/x で公開しているのはこちら。
deno.land/x/twitter_oauth_1_0a
以下メモになるので、「いいからソースとサンプルを見せろ」という方はgithubを見てもらった方がイイです。
以下ソースコードは有りません。
参考
公式
- developer.twitter.com - 認証 - OAuth 1.0a
- developer.twitter.com - 認証 - 署名の作成
- developer.twitter.com - 認証 - POST oauth/request_token
- developer.twitter.com - 認証 - POST oauth/access_token
PHP JavaScript での実装例
- Syncer Twitter REST APIの使い方
- 30歳からのプログラミング - Node.jsでTwitterAPIのリクエストトークンを取得
- github - PLhery/node-twitter-api-v2
- Qiita - Deno 上の JS で OAuth 認証して Twitter API を使用する
見たけど、設計方針が違うのであまり参考にできていないとも感じる
その他
- deno.land/x/hmac@v2.0.1 これが無かったらおそらく詰んでいた
- deno.land/x/case@v2.1.0
- Qiita -【TypeScript】Generics(ジェネリックス)を理解する
- note - deno で Twitter API の PIN-Based Auth を実装している話12月くらいにこの方も同じようなものを作っていたよう。
deno.land/x/hmac の選定はこちらを参考にさせていただいた
ユーザー情報取得までの流れ
1 | POST https://api.twitter.com/oauth/request_token?oauth_callback=XXXXXXXXXXXX トークンを取得 |
作成した twitter_oauth_1_0a(deno_twitter_oauth) はこの中でアクセストークン取得までを担当。
実装
/oauth/request_token にアクセス
認証 - 署名の作成 が参考になるが、鵜呑みにできなかった。
アクセストークンの作成までに署名の作成タイミングが 2 回有ることに最初気が付かなくて、1 回目に特化したものを作って作り直す羽目になった。
反省でしかない。
署名は、署名ベースと署名キーを使うそれぞれの作成方法と含めるパラメータが大事。
/oauth/request_token の署名作成
キーベースに含む文字列は、次の手順で作成。
パラメータ名 | 値 |
---|---|
oauth_consumer_key | < 開発者の用意したコンシュマーキー > |
oauth_timestamp | < タイムスタンプ(数字 10 桁) > |
oauth_nonce | < ランダムな値 > |
oauth_version | 1.0 |
oauth_signature_method | HMAC-SHA1 |
oauth_callback | 認証後のリダイレクト先 URL |
確認用にタイムスタンプは固定の値で試していたことも有ったが動作しているように見えた。
「現在の時刻」の値のリアルタイム性は、あまり重要でない可能性がある。
これを 次の手順で処理する。
- 署名のキーと値をパーセントエンコード(ただし、キーは文字列と_なのでエンコードしなくてよかった)
- キーのアルファベット順で並べ替えて
[キー]=[パーセントエンコードした値]
で文字列化3.
で作成した文字列を&
を挟んで連結[大文字のHTTPメソッド]&[パーセントエンコードしたリクエスト先URL]&[パーセントエンコードした4.]
で作成完了。
作ったものは、次のようになる。
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Doob%26oauth_consumer_key%3Dxvz1evFS4wEEPTGEFPHBog%26oauth_nonce%3DkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1318622958%26oauth_version%3D1.0"
署名キーは、次のパラメータで作成。
パラメータ名 | 値 |
---|---|
oauth_consumer_secret | < 開発者の用意したコンシュマーシークレット > |
[コンシュマーシークレット]&
を作成HMAC-SHA1 アルゴリズムで署名
署名完成
作ったものは次のようになる。KJmaxYxSHztR8Our3DFAqE2xBgw%3D
/oauth/request_token のヘッダーを作成
ヘッダーで要求されるパラメーターは次の通り。
パラメータ名 | 値 |
---|---|
oauth_consumer_key | < 開発者の用意したコンシュマーキー > |
oauth_timestamp | < タイムスタンプ(数字 10 桁) > |
oauth_nonce | < ランダムな値 > |
oauth_version | 1.0 |
oauth_signature_method | HMAC-SHA1 |
oauth_callback | 認証後のリダイレクト先 URL |
oauthSignature | 先に作った署名 |
- キーのアルファベット順で並べ替えて
[キー]=[値]
で文字列化10.
で作成した文字列を=
を挟んで連結11.
で作成した文字列を,
を挟んで連結OAuth [12. で作成した文字列]
を作成
この操作で、OAuth xxxxxxxxx~~
の文字列が作成できるので、これをヘッダーにつけてリクエストする。
この返り値に次の3つのパラメーターが返ってくる。
パラメーター | 用途 |
---|---|
oauth_token | ユーザーを twitter 画面にリダイレクトさせる際にパラメータにつける |
oauth_token_secret | アクセストークンを取る際に使うので一旦保存しておく(セッションなどでよい) |
oauth_callback_confirmed | true/false が返ってくるが今回は使わなかった。 |
後は、https://api.twitter.com/oauth/authenticate?oauth_token=[oauth_token]
の形にして、この URL へリダイレクトさせる。
/oauth/access_token にアクセス
Twitter 画面で認証すると、指定したコールバック URL に返ってくるので、次はアクセストークンを取得する。
作成方法は変わらないが、パラメーターが変わるので、以下の通り示す。
/oauth/access_token の署名作成
署名ベース作成のパラメーターは次の通り。
パラメータ名 | 値 |
---|---|
oauth_consumer_key | < 開発者の用意したコンシュマーキー > |
oauth_timestamp | < タイムスタンプ(数字 10 桁) > |
oauth_nonce | < ランダムな値 > |
oauth_version | 1.0 |
oauth_signature_method | HMAC-SHA1 |
署名キー作成のパラメーターは次の通り。
パラメータ名 | 値 |
---|---|
oauth_consumer_secret | < 開発者の用意したコンシュマーシークレット > |
oauth_token_secret |
キーは、6. [コンシュマーシークレット]&[OAuth トークンシークレット]
の形で作成。
/oauth/access_token のヘッダー作成
ヘッダー作成のパラメーターは次の通り。
パラメータ名 | 値 |
---|---|
oauth_consumer_key | < 開発者の用意したコンシュマーキー > |
oauth_timestamp | < タイムスタンプ(数字 10 桁) > |
oauth_nonce | < ランダムな値 > |
oauth_version | 1.0 |
oauth_signature_method | HMAC-SHA1 |
oauth_callback | 認証後のリダイレクト先 URL |
oauthSignature | 先に作った署名 |
oauth_token | < /oauth/request_token のレスポンスで取得したもの> |
oauth_verifier | < コールバック URL にアクセスの差異に付与されているパラメーター> |
これを使って、https://api.twitter.com/oauth/access_token
にアクセスすると認証したユーザーとして操作できるアクセストークンを入手できる。
結構気にしたこと
変数なるべくキャメルケースで書きたいなぁ
最終的に oauth_token とかに変形させたりするのが見えていたもののできるだけキャメルケースで書けるようにした。
しかし、戻ってきた値を動的にキャメルケースの形で詰め込みなおすのを断念したのが心残り。
TSだからか、動的にプロパティを生やす消すをし難いと感じたが、もうちょっと頑張ればできそうな気もする。
ちゃんとテスト書きたいなぁ
Deno.test をちゃんと使ってテストを今回は書いてみた。
しかし、どうしてもリダイレクトしたりAPIアクセスがあるのですべてを書けたわけではないのが心残り。
このあたりスタブを用意できると解決しそうなので用意してみたい。
派生形のような形で PIN ベース認証というものも作れるようなので、ここまではアップデートを継続しようかと考えているところ。
ではでは。