もどる TOP

[Twitter API] bot用のアクセストークンを取得する方法 (PHPでTwitterのOAuth認証)

 アプリ開発者自身のアクセストークンは、Twitterのアプリ管理画面の『Keys and Access Tokens』から簡単に発行できる。

 が、自分のアカウントを介して何かするアプリならそれでいいけど、botを作ろうとしたら面倒だった。別途作成したbot用のアカウント (第三者) に、開発者アカウントで作ったbotアプリを認証させる必要があるからだ。

 この認証が難しくて、個人的によく分かってなかったので、アクセストークンを取得して表示するだけのPHPを書いてみた。挙動は以下の通り。

  1. Twitter API/oauth/request_tokenを叩いてリクエストトークンを取得し、Twitter認証ページへのリンクを表示する。
  2. リンク先でTwitterの認証完了すると、コールバックURLとして設定済み (※後述・要設定) のこのスクリプトに戻ってくる。
  3. 戻ってくる時に連れてきたGETパラメータoauth_verifierを使ってTwitter API/oauth/access_tokenを叩き、アクセストークンを取得して表示する。
auth.php
<?php
const CONSUMER_KEY = '!! Consumer Key (API Key) を入力 !!';
const CONSUMER_SECRET = '!! Consumer Secret (API Secret) を入力 !!';

session_set_cookie_params(600);
session_start();

try {
	if (empty($_GET)) {
		//--------------------------------------
		// 1. 最初にアクセスした時
		//--------------------------------------
		// セッション削除
		unset($_SESSION['oauth_token']);
		unset($_SESSION['oauth_token_secret']);
		
		// APIを叩いてリクエストトークン取得して、セッションに保存
		$res = post(
			'https://api.twitter.com/oauth/request_token',
			[
				'oauth_callback' => '',
			]
		);
		if (!isset($res['oauth_token'])) {
			throw new Exception('レスポンス→ '.var_export($res, true));
		}
		$_SESSION['oauth_token'] = $res['oauth_token'];
		$_SESSION['oauth_token_secret'] = $res['oauth_token_secret'];

		// リクエストトークンを持ってTiwtterの認証画面に行くリンクを表示
		header('Content-Type: text/html');
		$url = 'https://api.twitter.com/oauth/authenticate?oauth_token='.$res['oauth_token'];
		echo '<a href="'.$url.'">'.$url.'</a>';
	}
	else {
		//--------------------------------------
		// 2. Twitterで認証して戻ってきた時
		//--------------------------------------
		// もらったパラメータ『oauth_verifier』をつけてAPIを叩き、アクセストークン取得
		$res = post(
			'https://api.twitter.com/oauth/access_token',
			[
				'oauth_verifier' => $_GET['oauth_verifier'],
			],
			$_SESSION['oauth_token'],       // セッションに保存していたリクエストトークンを署名に使う
			$_SESSION['oauth_token_secret'] // 同上
		);
		if (!isset($res['oauth_token'])) {
			throw new Exception('レスポンス→ '.var_export($res, true));
		}
		
		// アクセストークンを画面に表示
		header('Content-Type: text/html');
		echo implode([
			'成功!',
			'Access Token: '.$res['oauth_token'],
			'Access Token Secret: '.$res['oauth_token_secret'],
			'User ID: '.$res['user_id'],
			'Screen Name: '.$res['screen_name'],
		], '<br />');
	}
}
catch (Exception $e) {
	header('Content-Type: text/plain');
	echo '失敗!: '.$e->getMessage();
}

/**
 * 対象URLにOAuthの署名つきでPOSTし、結果を連想配列で返却する
 */
function post($url, $params, $token = null, $secret = null) {
	// curlでPOST
	$ch = curl_init();
	curl_setopt_array($ch, [
		CURLOPT_URL => $url,
		CURLOPT_HTTPHEADER => [
			createOAuthHeader($url, $params, $token, $secret)
		],
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_SSL_VERIFYPEER => false,
		CURLOPT_POST => true,
		CURLOPT_POSTFIELDS => http_build_query($params),
	]);
	if (($res = curl_exec($ch)) === false) {
		throw new Exception('通信時にエラーが発生しました。');
	}
	curl_close($ch);
	parse_str($res, $resArr);
	return $resArr;
}

/**
 * OAuth用のヘッダを作成して返却する
 */
function createOAuthHeader($url, $params, $token, $secret) {
	$sigparams = [
		'oauth_consumer_key'     => CONSUMER_KEY,
		'oauth_signature_method' => 'HMAC-SHA1',
		'oauth_timestamp'        => time(),
		'oauth_nonce'            => md5(uniqid(rand(), true)),
		'oauth_version'          => '1.0',
	];
	if (isset($token)) {
		// リクエストトークンがあればセット
		$sigparams['oauth_token'] = $token;
	}
	$sigparams += $params;
	
	// ルール通りに署名を作成してセット
	// https://developer.twitter.com/en/docs/basics/authentication/guides/creating-a-signature.html
	ksort($sigparams);
	$data = 'POST&'.rawurlencode($url).'&'.rawurlencode(http_build_query($sigparams, '', '&', PHP_QUERY_RFC3986));
	$key  = rawurlencode(CONSUMER_SECRET).'&';
	$key .= isset($secret) ? rawurlencode($secret) : ''; // リクエストトークンがあればセット
	$hash = hash_hmac('sha1', $data, $key, true);
	$sigparams['oauth_signature'] =  base64_encode($hash);

	// ヘッダ文字列にして返却
	return 'Authorization: OAuth '.http_build_query($sigparams, '', ',');
}

準備

 動かすのにいくつか準備が必要。

  1. ソースコードをローカルサーバー上に置く。ここではファイル名auth.phpとし、ローカルサーバー上のURLはhttp://localhost/auth.phpとする。
  2. アプリ管理画面の『Keys and Access Tokens』で『Consumer Key』『Consumer Secret』を確認し、ソースコード先頭の定数CONSUMER_KEYCONSUMER_SECRETにそれぞれ設定する。
  3. アプリ管理画面の『Settings』の『Callback URLs』にhttp://localhost/auth.phpを設定する。

 Twitterで認証後に戻されるページ (コールバックURL) が『Callback URLs』である。画面下部の『Update Settings』ボタンを押して反映するのを忘れないように。もちろんアクセストークンをメモった後はこの設定を消して大丈夫。

 リクエストトークン取得時にAPIに渡しているパラメータにもoauth_callbackというのがあるが、localhostのURLだとこれは使えない?らしい。

動かし方

 上記の準備を行ったら、以下の通りに動かす。

  1. Cookieが有効なブラウザで、http://localhost/auth.phpにアクセスする。Twitterの認証画面のURLリンクが表示されるのでクリック。
  2. Twitterの認証画面に飛ぶので、BOTのアカウントでログインして認証する。
  3. 認証完了後、元の画面に戻ってくる。アクセストークンが表示されていれば成功。

 成功すると、↓こんな感じの画面になる。

こんな感じ

 とにかく、APIを叩くときに作る署名が面倒くさい。ここでは関係無いが、ツイート等でパラメータにスペースが入ってる時は、署名に含めるパラメータのところでhttp_build_queryのエンコード方式 (第4引数) にRFC3986を明示的に指定しないと、スペースの扱いの違いで「{"code":32,"message":"Could not authenticate you."}」エラーになるようだ。

サイドバーを表示する
ブログ
ShortCircuit
ShortCircuit
花火大会
天使
去る512時間前、キリウ君は折れてない千歳飴を渡してきて、ぼくが折るよう仕向けた。1024時間前、彼はこの世のものではないハッシュアルゴリズムでひとりブロックチェーンを始めていた。