ゼロから学ぶOAuth

第2回OAuth Consumerの実装(入門 : OAuth Access Tokenの取得と利用)

OAuth Consumerサンプルを動かす

第1回では実際にOAuthを利用したサービスを触り、ユーザから見たOAuthを理解しました。またOAuthの大まかな処理フローについても触れました。

第2回と第3回では、OAuth Consumerの実装を通じてより深くOAuthを理解します。とは言っても、ゼロからアプリケーションを実装していくのには限界があるので、ここではあらかじめ(Ruby on Railsで)実装したサンプルアプリケーションを使います。なお、ConsumerとService Providerの実装は、すべてrailsを用いて行います。

Ruby on Railsの構築に関しては、技術評論社WEB+DB PRESSRubyist Magazineの記事などをご覧ください。

まずはgithubに公開されているoauth_sampleを動かしてみてください。gitをお使いの方は以下のコマンドで。gitをお使いでない方は、oauth_sampleからzipかtar形式でダウンロードしてください。

git clone git://github.com/nov/oauth_sample.git

その後railsアプリを起動します。筆者のMacBook上では以下で問題なく起動しますが、皆さんの環境でもそうであることを祈ります(サンプルが動かない場合は、githubのwikiページにあるコメント欄へコメントください⁠⁠。

gem install sqlite3-ruby
gem install oauth
cd oauth_sample/oauth_consumer
mkdir log
rake db:migrate
./script/server

http://localhost:3000にアクセスし、適当なユーザ名でログインすると、dashboardが表示されます。

smart.fmにOAuth Consumer登録

サンプルアプリケーションのdashboardには「new consumer」「new access token」というリンクが存在しますが、Access Tokenの取得にはConsumerの情報が必要なので、最初は「new consumer」からConsumer情報を登録します。

図1 Consumer情報の登録
図1 Consumer情報の登録

このアプリは、デフォルトの状態ではsmart.fmとGoogleの2つのOAuth Service Providerに対応しています。もちろんどちらも利用できますが、GoogleでのOAuth Consumer登録にはドメイン認証などが必要なので、ここではsmart.fmでConsumer登録を行います。smart.fmのConsumer登録はsmart.fm OAuth Client Applicationsから行えます。

図2 smart.fm OAuth Client Applications
図2 smart.fm OAuth Client Applications

今回のアプリケーションを利用する場合、登録フォームには以下のURLを入れてください。

  • Main Application URL : http://localhost:3000
  • Callback URL : http://localhost:3000/oauth/smartfm/callback

登録後、得られたConsumer KeyとConsumer SecretをサンプルアプリケーションのConsumer登録フォームに入力します。またsmart.fm APIではConsumer Keyとは別にAPI Keyも必要ですので、smart.fm API 日本語ガイド「APIデベロッパアカウントの登録」からAPI Keyを取得し、そちらもサンプルアプリケーションのConsumer登録フォームに入力して、registerをクリックします。⁠Scopeは空白で結構です)これでOAuth Consumerの登録は完了です。

OAuth Access Tokenの取得

Consumer登録が完了したので、これでAccess Tokenを取得する準備は整っています。dashboardの「new access token」をクリックすると、smart.fm APIとGoogle Data APIsそれぞれにAccess Tokenの「establish」ボタンがあるので、smart.fm APIのボタンをクリックします。するとsmart.fmにリダイレクトされるので、⁠authorize access?」にチェックを入れて「save」をクリックします。

図3 ⁠authorize access?」にチェックを入れて「save」
図3 「authorize access」にチェックを入れて「save」s

これで再びdashboardにリダイレクトされて、Access Tokenが表示されているはずです。

さて、ここからはrailsのコードを見ながらこの動作を追っていきます。いったんDBをクリア(rake db:migrate:reset)してください。

サンプルアプリケーションで実際にAccess Token取得に関わるのは、以下の2つです。

  • OauthAccessTokensController(oauth_consumer/app/controllers/oauth_access_tokens_controller.rb)
  • OauthConsumer(oauth_consumer/app/models/oauth_consumer.rb)

Request Tokenの取得

smart.fm APIのestablishボタンをクリックすると、処理はOauthAccessTokensControllerのnewアクションに移ります。以下は実際のコードから重要な部分のみを抜粋したものです。

class OauthAccessTokensController < ApplicationController

  def new
    redirect_to request_token.authorize_url
  end

  private

  def request_token
    request_token = oauth_consumer.get_request_token
    session[:request_token] = request_token.token
    session[:request_token_secret] = request_token.secret
    request_token
  end

end

ここではまずrequest_tokenメソッド内でconsumerのget_request_tokenを呼び出してバックグラウンドでRequest Tokenを取得し、authorize_urlにユーザをリダイレクトさせます。ほとんどの処理はoauth gemが行うので、サンプルアプリケーション内には細かい処理は書かれていませんが、実際にどのような通信が行われているかはtcpflowを使って確認することができます。

sudo tcpflow -c

これを見ると、まず最初はRequest Tokenを取得する為に、Authorizationヘッダにconsumer_keyやnonce、signatureなどのOAuthに必要な情報を付与して、http://api.smart.fm/oauth/request_token(smart.fmのRequest Token取得endpoint)にアクセスしていることがわかります。

POST /oauth/request_token HTTP/1.1
Connection: close
Accept: */*
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth oauth_nonce="SOME_NONCE_IS_HERE", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1236450076", oauth_consumer_key="SMARTFM_CONSUMER_KEY", oauth_signature="SOME_SIGNATURE_IS_HERE", oauth_version="1.0"
Host: api.smart.fm
Content-Length: 32

そしてsmart.fmからのレスポンスには、以下のようにRequest TokenとRequest Token Secretが含まれています。

oauth_token=SMARTFM_REQUEST_TOKEN&oauth_token_secret=SMARTFM_REQUEST_TOKEN_SECRET

その後、得られたRequest TokenをURLに付与して、http://smart.fm/oauth/authorize?oauth_token=SMARTFM_REQUEST_TOKENというURLにアクセスしています。このリダイレクト先で、ユーザはRequest Tokenに認可を与えるかどうか確認されることになります。

Request TokenとAccess Tokenの交換

ユーザがsmart.fm上でRequest Tokenに認可を与えると、ブラウザはOauthAccessTokensControllerのcreateアクション(http://localhost:3000/oauth/smartfm/callback)にリダイレクトされます。その際、認可済のRequest Tokenがoauth_tokenというパラメータで返されます。

class OauthAccessTokensController < ApplicationController

  def create
    new_access_token = oauth_consumer.get_access_token(params[:oauth_token], session[:request_token_secret])
    store_access_token(new_access_token)
    redirect_to_dashboard
  end

  private

  def store_access_token(access_token)
    OauthAccessToken.create(
      :user => current_user,
      :oauth_consumer => oauth_consumer,
      :token => access_token.token,
      :secret => access_token.secret
    )
  end

end

createアクションでは、あらかじめセッションに保存しておいたrequest_token_secretと認可済のtoken(params[:oauth_token])を引数として、consumerのget_access_tokenを呼び出しています。実際のtcpflowを見ると、バックグラウンドでAccess Token発行endpointのhttp://api.smart.fm/oauth/access_tokenにアクセスしていることがわかります。このリクエストでは、Authorizationヘッダに認可済のRequest Tokenが含まれていることもわかるでしょう。

POST /oauth/access_token HTTP/1.1
Connection: close
Accept: */*
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth oauth_nonce="SOME_NONCE_IS_HERE", oauth_signature_method="HMAC-SHA1", oauth_token="SMARTFM_REQUEST_TOKEN", oauth_timestamp="1236452101", oauth_consumer_key="SMARTFM_CONSUMER_KEY", oauth_signature="SOME_SIGNATURE_IS_HERE", oauth_version="1.0"
Host: api.smart.fm
Content-Length: 32

api.smart.fm上でRequest Tokenの認可が確認されると、以下のようにAccess Tokenが返されます。

oauth_token=SMARTFM_ACCESS_TOKEN&oauth_token_secret=SMARTFM_ACCESS_TOKEN_SECRET

サンプルアプリケーションではstore_access_tokenメソッドでAccess TokenをDBに保存しています。ここではsmart.fm上のユーザ名などは保存していませんが、必要があればService Provider上でのユーザ識別子も一緒に保存するようにした方が良いでしょう。⁠Service Provider上のユーザ識別子が必要かどうかや、それを得る方法は、各Service ProviderおよびAPI Callによって異なるので、詳しくはService Providerのドキュメントを確認してください。)

Access Tokenを使ってみる

最後に得られたAccess Tokenを利用して、smart.fmのリスト作成APIを呼び出してみましょう。以下のサンプルコードに、既に得られているAPI KeyやConsumer Key、Access Tokenなどをセットして、実行してみてください。正常にリスト作成が完了すれば、response.bodyにリストIDが入っているはずです。http://smart.fm/lists/:list_idにアクセスすれば、実際に作成されたリストが確認できます。

require 'rubygems'
require 'oauth/consumer'

SMARTFM_API_KEY     = 'YOUR_API_KEY'
CONSUMER_KEY        = 'YOUR_CONSUMER_KEY'
CONSUMER_SECRET     = 'YOUR_CONSUMER_SECRET'
ACCESS_TOKEN        = 'USER_ACCESS_TOKEN'
ACCESS_TOKEN_SECRET = 'USER_ACCESS_TOKEN_SECRET'

consumer = OAuth::Consumer.new(
  CONSUMER_KEY,
  CONSUMER_SECRET,
  :site => "http://api.smart.fm",
  :authorize_url => "http://smart.fm/oauth/authorize"
)
access_token = OAuth::AccessToken.new(consumer, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
response = access_token.post(
  '/lists',
  { :api_key                     => SMARTFM_API_KEY,
    'list[name]'                 => 'OAuth test',
    'list[description]'          => 'A list for OAuth test',
    'list[language]'             => 'en',
    'list[translation_language]' => 'ja' })

puts response.inspect, response.body

まとめ

今回はOAuth Consumerのサンプルアプリケーションとtcpflowを用いて、Consumerの振る舞いを確認しました。次回はより詳細なoauth gemの利用方法についてご紹介します。

おすすめ記事

記事・ニュース一覧