OAuth1.0の署名(Signature)を作成する方法
公開日: 2014/08/09 / 更新日:
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_secretとoauth_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ステップで構成される「単純な作業」です。「キー」と「データ」の作り方、そして「変換方法」を次の章で覚えてしまいましょう。
- 「キー」を作成する。
- 「データ」を作成する。
- 「キー」と「データ」を、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: キーの作成
MAC-SHA1の変換方式を用いるためには、「データ」と「キー」が必要です。まずは「キー」を作成してみましょう。その作り方は簡単で、oauth_consumer_secretとoauth_token_secretをURLエンコードして、&
で繋げるだけです。
ほとんどの場合、oauth_consumer_secretとoauth_token_secretの値は半角英数字なのでURLエンコードをしても意味がありません。が、定義上そうなっていることを覚えておきましょう。
bbbbbb&dddddd
oauth_token_secretが存在しない場合
OAuth1.0認証をしている上でoauth_token_secretの値がまだ存在しないケースがあります。その場合は次のようにoauth_token_secretをなし(空の文字列)にしてキーを作成して下さい。
bbbbbb&
サンプルコード
キーを作成するサンプルコードです。
PHP (oauth1.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 ;
// 確認用 (本番では消して下さい)
var_dump( $signature_key ) ;
手順2: データの作成
続いて「データ」を作成していきましょう。作成方法は次の通り、5ステップの構成です。
- パラメータをアルファベット順に
キー=値&キー=値&...
と繋ぐ。 - 組み立てたパラメータを、URLエンコードする。
- リクエストメソッドを、URLエンコードする。
- リクエストURLを、URLエンコードする。
- リクエストメソッド、リクエストURL、パラメータの順番に
&
で繋げる。
パラメータの組み立て
まずは1番です。パラメータをアルファベット順に、キー=値&キー=値&...
という形式に組み立てます。サンプルのパラメータを用いると、name
、text
、title
をアルファベット順に並び替えて次のようになりますね。
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 (oauth1.php)
<?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 ;
// 確認用 (本番では消して下さい)
var_dump( $signature_data ) ;
手順3: キーとデータを署名に変換
仕上げに作成した「データ」と「キー」を使って署名を作成します。次の手順になります。
- 「データ」「キー」を用いて、HMAC-SHA1方式のハッシュ値を生成する。
- ハッシュ値をbase64エンコードする。
HMAC-SHA1方式のハッシュ値に変換
まず、データ()とキー(
)を使って、HMAC-SHA1方式のハッシュ値を生成します。PHPでは次の通りです。
PHP
// HMAC-SHA1方式のハッシュ値に変換
$hash = hash_hmac( "sha1", $signature_data, $signature_key, TRUE ) ;
ハッシュ値をbase64エンコード
最後に出来上がったハッシュ値()をbase64エンコードして署名の完成となります。
PHP
// ハッシュ値をbase64エンコード
$signature = base64_encode( $hash ) ;
完成した署名
サンプルを元にした署名()は次の通りとなります。自分がやったものと照らし合わせてみて下さいね!
mu4s4b2t4T0HsjD0z0J749fMGPA=
サンプルコード
署名を作成する一連の流れを1つのプログラムにまとめてみました。パラメータを色々と変更して、署名がどのように作成されるのか、確認してみて下さい。
PHP (oauth1.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' ,
) ;
// 連想配列のキーをアルファベット順に並び替える
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]の内容を出力
echo $html ;