Webアプリに「GitHubで認証」ボタンを付けてログインさせる方法。
アプリを登録
https://github.com/settings/applications
からRegister new Applicationする。
ローカルで試すので、URLとコールバックURLはこうしておく
自分のアプリケーションのIDとsecret keyがもらえるのでメモしておく。(あとで使う)
OAuthする
ここに手順が書いてある。この通りにやればOAuthのtokenが手に入る。
OAuth | GitHub API
tokenが手に入れば、あとは
octokitなどにtokenを渡せばそのユーザーの権限でAPIを使わせてもらえる。
手順はおおまかに
1. GET https://github.com/login/oauth/authorize
ユーザーのWebブラウザをGETパラメータにアプリケーションID付けて上のURLにredirectする。
OAuthの承認画面が表示され、OKされればアプリ登録時に設定したURLにcallbackされる。
2. コールバックから”code”を取り出す。
callback URLに指定した通り、ユーザーのWebブラウザで http://localhost:5000/auth.callback が開かれる。
その時にGETパラメータで”code”が付いているので、実際のURLは
http://localhost:5000/auth.callback?code=1234abcd56
こうなる。
codeを取っておく。
3. POST https://github.com/login/oauth/access_token
Sinatraから上のURLにPOSTする。
“code”とアプリケーションIDとsecretをPOSTすると、ようやくOAuthのtokenが得られる。
4. tokenでOAuth認証
tokenで認証して、ようやく「この人がGitHub上でなんというアカウント名なのか」「持っているリポジトリ一覧」などが取得できるようになる。
ここからはoctokit使えばいいと思う。
なお1の時にscope(読み書き権限の詳細)やstate(クロスサイトリクエスト対策の文字列)を付ける事もできる。
無くても一応動く。
実装
起動前にRegister new Applicationした時に得たアプリケーションIDとsecretを環境変数に入れておく。
export GITHUB_APP_ID=a1b2cdef344565677asdf
export GITHUB_APP_SECRET=asdfhujikohujiko123456
あとはこのアプリを起動して、 /auth に移動させれば認証できる。
require "sinatra"
require "uri"
require "httparty"
get '/auth' do
query = {
:client_id => ENV["GITHUB_APP_ID"],
:redirect_uri => "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}/auth.callback",
}.map{|k,v|
"#{k}=#{URI.encode v}"
}.join("&")
redirect "https://github.com/login/oauth/authorize?#{query}"
end
get '/auth.callback' do
code = params["code"]
halt 400, "bad request (code)" if code.to_s.empty?
## get oauth token
query = {
:body => {
:client_id => ENV["GITHUB_APP_ID"],
:client_secret => ENV["GITHUB_APP_SECRET"],
:code => code
},
:headers => {
"Accept" => "application/json"
}
}
res = HTTParty.post("https://github.com/login/oauth/access_token", query)
halt 500, "github auth error" unless res.code == 200
begin
token = JSON.parse(res.body)["access_token"] ## tokenを取得!
rescue
halt 500, "github auth error"
end
## sessionに保存するなど自由に
redirect '/'
end
取得したtokenは
octokitで使える。
require 'octokit'
client = Octokit::Client.new :oauth_token => token
user = client.user
user.avatar_url # アイコン画像