こうこく
作 ▸
改 ▸

Twitter APIでアカウント認証してアクセストークン取得するサンプル

PHPでTwitterのOAuth認証をする方法。

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

が、自分のアカウントを介して何かするアプリならそれでいいけど、例えば開発者アカで作ったbotアプリをbot用の別アカウントに認証させようと思ったら、面倒です。なので、認証してアクセストークンを表示するだけのサンプルを書いてみました。

このページのサンプルの挙動は以下の通りです。

  1. /oauth/request_token を叩いてリクエストトークン取得し、Twitter認証ページへのリンクを表示する。
  2. リンク先でTwitterの認証を完了すると、コールバックURLとして設定済み (※後述・要設定) のこのスクリプトに戻ってくる。
  3. 戻ってくる時に連れてきたGETパラメータ oauth_verifier を使って /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' => '', // localhostだとこれは使えないらしいのでカラ。
			]
		);
		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)); // ここでは関係無いが、パラメータにスペースが含まれてる時用に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, '', ',');
}

それにしても、APIを叩くときに作る署名がとにかく面倒くさいです。ちょっと間違えるとすぐ {"code":32,"message":"Could not authenticate you."} エラーになるし。

動かし方

最初に準備が必要です。

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

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

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

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

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

こんな感じ
こんな感じ

この記事に何かあればこちらまで (非公開)