Python/FlaskアプリからOAuthでGitHub APIを使う
このようなサンプルが意外と見つからなかったので作りました。
GitHub API
GitHubはWeb API を提供しており、リポジトリやユーザーなどをAPI経由で取得・操作することができます。
執筆時の2014年2月現在では、v3
とbeta
の2つのバージョンがあり、デフォルトはbeta
です。ややわかりにくい名前付けですが、beta
のほうが古いようで、2014年4月15日からv3
がデフォルトになる予定です。
利用するバージョンはHTTPリクエストのAccept
ヘッダーで指定できます。v3
とbeta
の違いはあまり大きくないみたいなので、現時点では特に指定せずにデフォルトのバージョンを使っても問題なさそうです。
認証方法 としては、Basic認証、OAuth2 Token、OAuth2 Key/Secretの3種類が利用できます。 今回は、Flaskを利用したWebアプリなので、OAuth2 Tokenを利用します。
PythonでOAuth2
oauth2というStarがたくさんついたライブラリがありますが、2年以上メンテナンスされておらず、名前の割にOAuth2には対応していないようです。
フォークされたものもありますが、メンテナンスされておりStarも多いRauthが良さそうだったので利用します。
Rauthは内部でいい感じに Requests を使っており、使いやすいです。
サンプルアプリケーション
以下のようなアプリを作りました。GitHubで公開しています。
# coding: utf-8 import os import binascii from flask import Flask, request, session, abort, redirect from rauth import OAuth2Service # Read secret keys from env vars # See: http://12factor.net/config GITHUB_CLIENT_ID = os.environ['GITHUB_CLIENT_ID'] GITHUB_CLIENT_SECRET = os.environ['GITHUB_CLIENT_SECRET'] app = Flask(__name__) app.secret_key = os.environ['SESSION_SECRET_KEY'] # necessary for session # Set up service wrapper for GitHub # - `client_id` and `client_secret`: available in an application page of GitHub # - `name`: name for human # - `authorize_url` and `access_token_url`: available in the GitHub's developer guide # http://developer.github.com/v3/oauth/#web-application-flow # - `base_url`: base url for calling API github = OAuth2Service( client_id=GITHUB_CLIENT_ID, client_secret=GITHUB_CLIENT_SECRET, name='github', authorize_url='https://github.com/login/oauth/authorize', access_token_url='https://github.com/login/oauth/access_token', base_url='https://api.github.com/') @app.route('/') def top(): """ Top page """ # For authorized users, show welcome message and links if 'username' in session: return 'Welcome @{0}! <a href="/repos">Repos</a> <a href="/logout">Logout</a>'.format( session['username']) # Generte and store a state in session before calling authorize_url if 'oauth_state' not in session: session['oauth_state'] = binascii.hexlify(os.urandom(24)) # For unauthorized users, show link to sign in authorize_url = github.get_authorize_url(scope='', state=session['oauth_state']) return '<a href="{0}">Sign in with GitHub</a>'.format(authorize_url) @app.route('/callback/github') def callback(): """ OAuth callback from GitHub """ code = request.args['code'] state = request.args['state'].encode('utf-8') # Validate state param to prevent CSRF if state != session['oauth_state']: abort(400) # Request access token auth_session = github.get_auth_session(data={'code': code}) session['access_token'] = auth_session.access_token # Call API to retrieve username. # `auth_session` is a wrapper object of requests with oauth access token r = auth_session.get('/user') session['username'] = r.json()['login'] return redirect('/') @app.route('/logout') def logout(): """ Logout """ # Delete session data session.pop('username') session.pop('access_token') return redirect('/') @app.route('/repos') def repos(): """ List recently updated repositories """ # Restore auth_session from the access_token stored in session auth_session = github.get_session(session['access_token']) r = auth_session.get('/user/repos', params={'sort': 'updated'}) repos = r.json() list_items = [] for repo in repos: list_items.append('<li>{0}</li>'.format(repo['full_name'])) return '<ul>{0}</ul>'.format('\n'.join(list_items)) if __name__ == '__main__': app.run(debug=True)
前提
Foremanですが、Rubyの環境を作るのが面倒な場合は、バイナリ1つで実行できるforegoがお勧めです。Go言語++
動かすまでの手順
1. GitHubでアプリケーションを登録
https://github.com/settings/applications/new でアプリケーションを新規登録します。
Authorization callback URL
は http://localhost:5000/callback/github
とします。
リダイレクトされるだけなので、ローカルアドレスで大丈夫です。
2. クローンして依存関係をインストール
$ git clone https://github.com/orangain/example-github-oauth-flask.git $ cd example-github-oauth-flask $ virtualenv --python=python3 venv # virtualenvを使う場合 $ . venv/bin/activate # virtualenvを使う場合 (venv)$ pip install -r requirements.txt
執筆時点で最新のRauth 0.6.2が依存するRequests 1.3.2では、インストール時にSyntax Errorが表示されますが、特に問題なく使えます。
3. 設定ファイルを配置
example-github-oauth-flask/.env
を以下の内容で作成します。リポジトリに入れるとマズイ設定項目は環境変数から読み込むのが 12factor のやり方です。
GITHUB_CLIENT_ID=(1で作成したアプリのClient ID) GITHUB_CLIENT_SECRET=(1で作成したアプリのClient ID Secret) SESSION_SECRET_KEY=(ランダムな文字列)
4. サーバーを起動
(venv)$ foreman run python github_oauth.py
これで、 http://localhost:5000/ にアクセスすれば以下のようなページが表示され、GitHubのAPIを利用できます。