ゼロから学ぶOAuth

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

この記事を読むのに必要な時間:およそ 4 分

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の利用方法についてご紹介します。

著者プロフィール

真武信和(またけのぶかず)

Cerego Japan Inc.で働くWebエンジニア。

smart.fmで外部APIとの連携機能(OAuth Consumer)の開発に携わるほか、smart.fm API(OAuth Service Provider)の開発にも携わっている。

URL:
http://matake.jp/
http://smart.fm/users/matake