【Twitter API】OAuth2.0認証でAPIを使用してみる
概要
2021年の末頃に、Twitter APIのOAuth2.0認証がリリースされました。基本的に今後APIを使用する際はOAuth2.0認証を使用したほうが良いと思いますが、2022年9月時点で、そこまで情報等が多くないと感じたので、今回実装のサンプルを紹介します。
事前知識など
Twitter APIのOAuth2.0認証の概要については、下記の記事で概要がまとめられています。これらの記事の情報を元に実装していきます。
Twitter OAuth2.0の設定や動作まとめ
Twitter api v2でOAuth2.0認証でtweetする
実装方針
- フロントエンド(Next.jsを使用)と、バックエンド(PHPを使用)に分けて実装します。
- フロントエンドでは認可コードを取得するまで、バックエンドではアクセストークンの取得とユーザ情報の取得を行います。理由としてアクセストークンの取得には、Twitterの
ClientSecret
の情報が必要になり、これをフロントに晒すのは避けたいためです。
実装サンプル
【フロントエンドの実装】
まずはTwitterの認証画面に、遷移させる箇所の実装です。
ランダム文字列の生成にはrandomstringというライブラリを使用しています。また、s256形式でのcode_challenge
の生成はPKCEをJavaScriptで実装するの記事を参考にしています。
codeVerifier
の値はTiwtterから戻って来た時に使いたいので、sessionStorageに保存しています。
import randomstring from "randomstring";
import base64url from "base64url";
import jsSha256 from "js-sha256";
export default function AuthTwitterRegisterComponent() {
async function onClickTwitterAuth() {
const state = randomstring.generate(50);
const codeVerifier = randomstring.generate(50);
// リダイレクトで戻る時に使いたいのでsessionStorageに保存
sessionStorage.setItem("codeVerifier", codeVerifier);
const twitterOAuth2Url =
`https://twitter.com/i/oauth2/authorize?` +
`response_type=code&` +
`client_id=${process.env.NEXT_PUBLIC_TWITTER_CLIENT_ID}&` +
`redirect_uri=${location.protocol}//${location.host}/auth/twitter_redirect&` +
`scope=tweet.read%20users.read&` +
`state=${state}&` +
`code_challenge=${base64url(jsSha256.arrayBuffer(codeVerifier))}&` +
`code_challenge_method=s256`;
window.location.href = twitterOAuth2Url;
}
return (
<div className="w-64 flex justify-center items-center flex-col">
<button
className="w-64 bg-indigo-200 rounded px-4 py-2 border border-neutral-300"
onClick={onClickTwitterAuth}
>
Twitterにログイン
</button>
</div>
);
}
Twitterから戻ってきた後の実装です。
パラメータに認可コードが入ってるのでこれを取得するのと、sessionStorageに保存したcodeVerifier
を取得してバックエンドに渡します。
import Router, { useRouter } from "next/router";
export default function TwitterRedirect() {
const { query, isReady } = useRouter();
useEffect(() => {
if (isReady) {
const codeVerifier = sessionStorage.getItem("codeVerifier");
const { code } = query;
// sessionStorageは削除する
sessionStorage.removeItem("codeVerifier");
if (codeVerifier && code) {
// 認可コードとcodeVerifierをバックエンドに送信(記載は割愛)
・
・
・
} else {
// 値が取れなかったらトップに遷移
Router.push("/");
}
}
}, [isReady]);
return <></>;
}
【バックエンドの実装】
TwitterへのAPIはcurlを使って投げます。ログインユーザの情報はGET /2/users/meのAPIを使用します。
また、フロントエンドからパラメータを受け取る部分の実装は、記載割愛します。
<?php
namespace App\Services\Auth;
class TwitterAuthService
{
public function getUserInfoFromCode($authCode, $codeVerifier)
{
// access_tokenの取得
$chGetToken = curl_init();
curl_setopt($chGetToken, CURLOPT_POST, true);
curl_setopt($chGetToken, CURLOPT_URL, 'https://api.twitter.com/2/oauth2/token');
curl_setopt($chGetToken, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chGetToken, CURLOPT_USERPWD, sprintf('%s:%s', env('TWITTER_CLIENT_ID'), env('TWITTER_CLIENT_SECRET')));
curl_setopt($chGetToken, CURLOPT_POSTFIELDS, http_build_query(array(
'code' => $authCode,
'grant_type' => 'authorization_code',
'client_id' => env('TWITTER_CLIENT_ID'),
'redirect_uri' => env('FRONT_END_URL') . '/auth/twitter_redirect',
'code_verifier' => $codeVerifier,
)));
$accessToken = json_decode(curl_exec($chGetToken))->access_token;
// access_tokenを使ってログインユーザの情報を取得
$chUserToken = curl_init();
curl_setopt($chUserToken, CURLOPT_URL, 'https://api.twitter.com/2/users/me');
curl_setopt($chUserToken, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chUserToken, CURLOPT_HTTPHEADER, array('Content-Type: application/json', "Authorization: Bearer " . $accessToken));
$userInfo = json_decode(curl_exec($chUserToken))->data;
return $userInfo;
}
}
その他
TwitterにAPIを投げる時Client Forbidden
というエラーが発生し少しハマったのですが、Twitter APIで"Client Forbidden"エラーの記事にある通り、Twitter Developer Potalでプロジェクトを作成し忘れたからでした。。
Discussion