TwitterのOAuth認証を使ってみる

2014-11-12

ユーザログインが必要なウェブサービスを作りたいが、ユーザの心理的に新たなウェブサービスに対してユーザ名とパスワードを登録するのってハードルが高いと思う。そこで既存のサービスのアカウント情報を使ってログインできるようにしたい。

ここではTwitterの認証を使ってアカウント情報に紐付けるアプリを作ってみたい。アプリはHerokuを使ってデプロイする。言語はRuby、フレームワークはSinatraを使う。

コード, デモ Deploy

Twitterへのアプリの登録

Twitterの認証を使えるようにするために、Twitterにアプリを登録する。

  • Twitter Application Managementにアクセスして、 [Create New App] で新規アプリを登録する。
    • アプリ名、説明、ウェブサイト、コールバックURL を登録する
    • ウェブサイトとコールバックURLは適当に設定しておいて、Herokuでアプリをデプロイしてから 後でちゃんと設定する
    • コールバックURLは必須マークが付いてないけど、設定しないと動かなかった
    • コールバックURLはTwitterで認証が成功または失敗したときに呼び出される、アプリ側のURL となる

Sinatraでアプリの作成

実際にウェブアプリを作っていく。ここではシンプルにSinatraを使う。

source 'https://rubygems.org'
gem 'sinatra'
require 'sinatra'

get '/' do
erb :index
end
<!DOCTYPE html>
<html>
<body>
Hello, world
</body>
</html>

bundle install で必要なライブラリをインストールして、bundle exec ruby app.rb でサーバを起動させる。デフォルトだとローカルの http://localhost:4567/ でアクセスできる。

Twitter認証の呼び出し

TwitterのOAuthを使って認証をする。実際には gem の twitter_oauth を使う。

htmlで /request_token へのリンクを表示して、アクセスされたら実際に認証の手順を進める。

gem 'twitter_oauth'  # 追加
<a href="/request_token">Twitter Login</a>
require 'twitter_oauth'

enable :sessions

before do
key = 'Twitterアプリのコンシューマキー'
secret = 'Twitterアプリのコンシューマシークレット'
@twitter = TwitterOAuth::Client.new(
:consumer_key => key,
:consumer_secret => secret,
:token => session[:access_token],
:secret => session[:secret_token])
end

get '/request_token' do
callback_url = "#{base_url}/access_token"
request_token = @twitter.request_token(:oauth_callback => callback_url)
session[:request_token] = request_token.token
session[:request_token_secret] = request_token.secret
redirect request_token.authorize_url
end

def base_url
default_port = (request.scheme == "http") ? 80 : 443
port = (request.port == default_port) ? "" : ":#{request.port.to_s}"
"#{request.scheme}://#{request.host}#{port}"
end
  • Sinatraのbeforeフィルタを使って、TwitterOAuth::Clientを作成する
  • /request_tokengetでアクセスされた時、そのtwitter用のoauthクライアントの request_token を呼び出してやる。
    • :oauth_callback に認証が成功または失敗した時に呼び出してもらうURLを指定する
  • 後で認証結果を処理するときのために、セッションにリクエストのトークンとシークレットを 保存しておく

リンクをクリックするとアプリ情報を持ってTwitter側の request_token.authorize_url にリダイレクトされ、おなじみの連携画面が表示される:

認証画面

ここで連携を認証またはキャンセルすると、コールバックURL (/accesss_token) に戻ってくる。

認証結果の取得

Twitterから戻ってきた認証結果を取得する。

get '/access_token' do
begin
@access_token = @twitter.authorize(session[:request_token], session[:request_token_secret],
:oauth_verifier => params[:oauth_verifier])
rescue OAuth::Unauthorized => @exception
return erb :authorize_fail
end

session[:access_token] = @access_token.token
session[:access_token_secret] = @access_token.secret
session[:user_id] = @twitter.info['user_id']
session[:screen_name] = @twitter.info['screen_name']
session[:profile_image] = @twitter.info['profile_image_url_https']

redirect '/'
end
  • コールバックURLのパラメータに渡されたoauth_verifierが正しいかどうか、 TwitterOAuth::Client#authrizeで認証する。
  • 認証に成功したらinfo['user_id']にTwitterのユーザID、info['screen_name']に名前、 info['profile_image_url_https']にアイコン画像のURLが入っているので、アプリ側で 使える。
  • TwitterのAPIを使ってタイムラインを取得したりする場合にはアクセストークンとか アクセストークンシークレットを使う

Herokuにデプロイ

Herokuにデプロイできるようにするために、設定ファイルを追加する。

require 'bundler'
Bundler.require

require './app'
run Sinatra::Application

Herokuコマンドでアプリの登録などを行う

  • heroku login
  • heroku create
  • git push heroku master

キーやシークレットを環境変数から取得し、ソースに含めないようにする

Twitterのアプリのコンシューマキーやシークレットをソースに書いていたけどそれはあまりよくないし、githubなどにアップロードしてしまうのは問題がある。そこでソースコードからは外して環境変数に入れて使えるようにする。

環境変数に入れるにはシェルで設定する

$ export CONSUMER_KEY="..."
$ export CONSUMER_SECRET="..."

Sinatraアプリから参照するには ENV を通して

key = ENV['CONSUMER_KEY']
secret = ENV['CONSUMER_SECRET']

とできる。

Herokuで使えるようにするには heroku config:add で設定する:

$ heroku config:add CONSUMER_KEY="..."
$ heroku config:add CONSUMER_SECRET="..."

  • Sinatraでセッション情報をsessionに保存するけど、enable :sessionsを指定しないと ちゃんと保存できない?ことがある。でも指定するとセッション情報をすべてをクッキーで送る? とかいう情報があるので、ちゃんとした方がいいかも。
  • Twitterのアプリの設定画面に「Allow this application to be used to Sign in with Twitter」というチェックボックスがあるが、どういう項目かよくわからなかった