OAuth1.0の署名(Signature)を作成する方法

OAuth2.0が登場してからも、1.0を採用し続けるwebサービスはTwitter、Tumblr、500pxなど、まだまだ数多く残っています。今回は「OAuth 1.0認証における署名(Signature)の作成方法」を紹介します。なお、この記事で説明する署名の作成方式は「HMAC-SHA1」です。

OAuth1.0の署名とは?

署名って何?

署名とは、簡単に言うと、URLアドレスとパラメータ+αを暗号化したものです。「OAuth1.0」という認証方式を採用したAPIを利用する場合、リクエストするパラメータに応じて、「署名(Signature)」となるキー(暗号)を作成し、一緒に送信しなければいけません。APIを提供するサービス側は、アプリケーション側が送ってきたパラメータと、この署名を照合し、署名が正しくない場合、エラーを返します。これにより、不正な第三者のリクエストを防ぎます。

OAuthの仕組みを深く理解したい場合、下記文献が参考になります。内容は公式ドキュメント(英語)の方が充実していますが、分かりやすさを求めるのなら、まずWikipediaをご覧下さい。とはいえ、一番理解を助けるのは、実際にプログラミングをすることです。私は下記の文献をほとんど読んでいません。

HMAC-SHA1とは?

「HMAC-SHA1」とは、データの変換方式の1つです。OAuth1.0における署名を作成するには、この「HMAC-SHA1」という製法が多く用いられているというわけです。HMAC-SHA1製法を覚えておけば、世の中のOAuth1.0を採用したAPIのほとんどに対応できるはずです。例により、下記に参考文献を紹介しますが、読む前にプログラミングをした方が、理解は速いはずです。

署名作成に必要な要素

OAuth1.0認証における「署名」を作成するには通常、下記4つの値が必要です。その内、純粋に署名を作成する部分だけを見ればoauth_consumer_secretoauth_token_secretが必要となります。oauth_token_secretに関しては、存在しない場合は「なし」が値となります。

oauth_consumer_key
アプリケーションごとに割り当てられたID。webサービスによって「API Key」「Consumer Key」など名称が違う。
oauth_consumer_secret
oauth_consumer_keyの対となるキー。webサービスによって「API Secret」「Consumer Secret」など名称が違う。
oauth_token
アプリケーションを利用するアクセス、ユーザーごとに割り当てられたID。「リクエストトークン」「アクセストークン」など。
oauth_token_secret
oauth_tokenの対となるキー。「リクエストトークンシークレット」「アクセストークンシークレット」など。

署名作成の流れ

大仰な説明をしてきたものの、その実は、署名の作成は下記の3ステップで構成される「単純な作業」です。「キー」と「データ」の作り方、そして「変換方法」を次の章で覚えてしまいましょう。

  1. 「キー」を作成する。
  2. 「データ」を作成する。
  3. 「キー」と「データ」を、「HMAC-SHA1」を用いて署名に変換する。

プログラミング

サンプルリクエスト

ここからは、サンプルを用いて実際にOAuth1.0における署名(HMAC-SHA1方式)を作成していきます。下記が今回、想定するサンプルリクエストです。

リクエストURL(エンドポイント)
http://example.com/sample.php
リクエストメソッド
POST
パラメータ
title=AAA&name=BBB&text=CCC

また、次の値の「oauth_consumer_secret」「oauth_token_secret」を所有していると仮定します。

oauth_consumer_secret
bbbbbb
oauth_token_secret
dddddd

手順1: キーの作成

HMAC-SHA1の変換方式を用いるためには、「データ」と「キー」が必要です。まずは「キー」を作成してみましょう。その作り方は簡単で、oauth_consumer_secretoauth_token_secretをURLエンコードして、&で繋げるだけです。

bbbbbb&dddddd

oauth_consumer_secretoauth_token_secretの値は通常、英数字になるので、URLエンコードをしても実質的に意味はありません。が、定義上そうなっていることを覚えておきましょう。

oauth_token_secretが存在しない場合

OAuth1.0認証をしている上で、oauth_token_secretの値がまだ存在しないケースがあります。その場合は、次のようにoauth_token_secretを「なし」にしてキーを作成して下さい。

bbbbbb&

サンプルコード

PHP

<?php

	// oauth_consumer_secret
	$oauth_consumer_secret = 'bbbbbb' ;

	// [oauth_consumer_secret]をURLエンコード
	$encode_a = rawurlencode( $oauth_consumer_secret ) ;

	// oauth_token_secret
	$oauth_token_secret = 'dddddd' ;

	// [oauth_token_secret]をURLエンコード
	$encode_b = rawurlencode( $oauth_token_secret ) ;

	// 2つの値を[&]で繋いで署名キー[$signature_key]が完成する
	$signature_key = $encode_a . '&' . $encode_b ;

手順2: データの作成

続いて「データ」を作成していきましょう。作成方法は次の通り、5ステップの構成です。

  1. パラメータをアルファベット順に「キー=値&キー=値&...」と繋ぐ。
  2. 組み立てたパラメータを、URLエンコードする。
  3. リクエストメソッドを、URLエンコードする。
  4. リクエストURLを、URLエンコードする。
  5. リクエストメソッド、リクエストURL、パラメータの順番に&で繋げる。

パラメータの組み立て

まずは1番です。パラメータをアルファベット順に、「キー=値&キー=値&...」という形式に組み立てます。サンプルのパラメータを用いると、nametexttitleをアルファベット順に並び替えて次のようになりますね。

name=BBB&text=CCC&title=AAA

パラメータをエンコード

続いて、組み立てたパラメータをURLエンコードします。すると次のようになります。

name%3DBBB%26text%3DCCC%26title%3DAAA

リクエストメソッドをエンコード

リクエストメソッドを、URLエンコードします。元々、英字なので、実質的に意味はありませんが、形式的に行なっておきましょう。サンプルを元にすると次の通りです。

POST

リクエストURLをエンコード

続いて、リクエストURLを、URLエンコードします。サンプルを元にすると次の通りです。

http%3A%2F%2Fexample.com%2Fsample.php

3つの要素を&で繋ぐ

最後に、「リクエストメソッド」「リクエストURL」「パラメータ」の順番に&で繋げます。サンプルでは次の通りになります。分かりやすいように色分けをしてあります。

POST&http%3A%2F%2Fexample.com%2Fsample.php&name%3DBBB%26text%3DCCC%26title%3DAAA

これで、「データ」が完成しました。特に難しいところはなかったはずです。

PHP

// リクエストメソッド(URLエンコード)
	$request_method = rawurlencode( 'POST' ) ;

	// リクエストURL(URLエンコード)
	$request_url = rawurlencode( 'http://example.com/sample.php' ) ;

	// パラメータ(連想配列形式)
	$params = array(
		'title' => 'AAA' ,
		'name' => 'BBB' ,
		'text' => 'CCC' ,
	) ;

	// 連想配列のキーをアルファベット順に並び替える
	ksort( $params ) ;

	// 配列の各パラメータの値をURLエンコード
	foreach( $params as $key => $value )
	{
		$params[ $key ] = rawurlencode( $value ) ;
	}

	// 連想配列[$params]を[キー=値&キー=値]の形式に組み立てる
	$request_params = http_build_query( $params , '' , '&' ) ;

	// 組み立てたパラメータをURLエンコードする
	$request_params = rawurlencode( $request_params ) ;

	// メソッド[$request_method]、URL[$request_url]、パラメータ[$request_params]の順に[&]で繋げる
	$signature_data = $request_method . '&' . $request_url . '&' . $request_params ;

手順3: キーとデータを署名に変換

仕上げに、作成した「データ」と「キー」を使って、署名を作成します。次のような手順になりますが、1つ1つの処理、内容は現段階ではよく分からないままで大丈夫です。

  1. 「データ」「キー」を用いて、HMAC-SHA1方式のハッシュ値に変換する。
  2. ハッシュ値をbase64エンコードする。

HMAC-SHA1方式のハッシュ値に変換

まず、「データ($signature_data)」と「キー($signature_key)」を使って、HMAC-SHA1方式のハッシュ値に変換します。PHPでは次の通りになります。

PHP

// HMAC-SHA1方式のハッシュ値に変換
$hash = hash_hmac( 'sha1' , $signature_data , $signature_key , TRUE ) ;

ハッシュ値をbase64エンコード

最後に、出来上がった「ハッシュ値($hash)」を、base64エンコードして、署名の完成となります。

PHP

// ハッシュ値をbase64エンコード
$signature = base64_encode( $hash ) ;

完成した署名

サンプルを元にした署名($signature)は次の通りとなります。自分がやったものと照らし合わせてみて下さいね!

mu4s4b2t4T0HsjD0z0J749fMGPA=

サンプルコード

署名を作成する一連の流れをプログラムにしてみました。パラメータを色々と変更して、署名がどのように作成されるのか、確認してみて下さい。

PHP

<?php

	// oauth_consumer_secret
	$oauth_consumer_secret = 'bbbbbb' ;

	// [oauth_consumer_secret]をURLエンコード
	$encode_a = rawurlencode( $oauth_consumer_secret ) ;

	// oauth_token_secret
	$oauth_token_secret = 'dddddd' ;

	// [oauth_token_secret]をURLエンコード
	$encode_b = rawurlencode( $oauth_token_secret ) ;

	// 2つの値を[&]で繋いで署名キー[$signature_key]が完成する
	$signature_key = $encode_a . '&' . $encode_b ;

	// リクエストメソッド
	$request_method = 'POST' ;

	// リクエストURL
	$request_url = 'http://example.com/sample.php' ;

	// リクエストメソッドをURLエンコード
	$request_method = rawurlencode( $request_method ) ;

	// リクエストURLをエンコード
	$request_url = rawurlencode( $request_url ) ;

	// パラメータ(連想配列形式)
	$params = array(
		'title' => 'AAA' ,
		'name' => 'BBB' ,
		'text' => 'CCC' ,
	) ;

	// GETリクエストがある場合
	foreach( $params as $key => $value ) {
		if( isset($_GET[ $key ]) && !empty($_GET[ $key ]) ) {
			$params[ $key ] = $_GET[ $key ] ;
		}
	}

	// 連想配列のキーをアルファベット順に並び替える
	ksort( $params ) ;

	// 配列の各パラメータの値をURLエンコード
	foreach( $params as $key => $value ) {
		$params[ $key ] = rawurlencode( $value ) ;
	}

	// 連想配列[$params]を[キー=値&キー=値]の形式に組み立てる
	$request_params = http_build_query( $params , '' , '&' ) ;

	// 組み立てたパラメータをURLエンコードする
	$request_params = rawurlencode( $request_params ) ;

	// メソッド[$request_method]、URL[$request_url]、パラメータ[$request_params]の順に[&]で繋げる
	$signature_data = $request_method . '&' . $request_url . '&' . $request_params ;

	// HMAC-SHA1方式のハッシュ値に変換
	$hash = hash_hmac( 'sha1' , $signature_data , $signature_key , TRUE ) ;

	// ハッシュ値をbase64エンコードして署名の完成
	$signature = base64_encode( $hash ) ;

	// HTML用
	$html = '' ;

	// 実行結果
	$html .= '<h2>実行結果</h2>' ;
	$html .= '<dl>' ;
	$html .= 	'<dt>URL</dt>' ;
	$html .= 		'<dd>' . $request_url . '</dt>' ;
	$html .= 	'<dt>メソッド</dt>' ;
	$html .= 		'<dd>' . $request_method . '</dt>' ;
	$html .= 	'<dt>パラメータ</dt>' ;
	$html .= 		'<dd>' . $request_params . '</dt>' ;
	$html .= 	'<dt>完成した署名</dt>' ;
	$html .= 		'<dd>' . $signature . '</dt>' ;
	$html .= '</dl>' ;

	// パラメータの調整
	$html .= '<h2>パラメータの調整</h2>' ;
	$html .= '<p>パラメータを調整してみましょう。</p>' ;
	$html .= '<form>' ;
	$html .= 	'<dl>' ;

	foreach( $params as $key => $value ) {
		$html .= 	'<dt>' . $key . '</dt>' ;
		$html .= 		'<dd><input type="text" name="' . $key . '" value="' . htmlspecialchars( rawurldecode( $value ) , ENT_QUOTES , 'UTF-8' ) . '"></dt>' ;
	}

	$html .= 	'</dl>' ;
	$html .= 	'<p><button>パラメータを変更</button></p>' ;
	$html .= '</form>' ;

	// ブラウザに[$html]の内容を出力
	// 運用時はHTMLのヘッダーとフッターを付けましょう。
	echo $html ;

デモを見る (VIEW DEMO)

ダウンロード

この記事で紹介したサンプルコードをダウンロードできます。ご活用下さい。

ファイル一覧

SYNCER000059
make-oauth-signature.php Download
readme.txt Download

ファイル名をクリックすると内容を確認できます。「Download Zip」をクリックするとファイル一式をダウンロードできます。

ご利用の際は、付属のREADMEファイル(readme.txt)をご確認下さい。

Download Zip