Python から OAuth 2 な API を利用する際に、urllib
+ oauthlib
を使った場合の具体的なやり方がググっても出てこなかったので、自分でやってみた。
今回は例として Netatmo API について記述しているが、OAuth 2 に対応した API であればやり方はほとんど変わらないはず。
なぜ urllib + oauthlib か
urllib
は HTTP リクエストを送るライブラリとしてよくまとまっていて、oauthlib
は OAuth に関する処理を行うライブラリとしてよくまとまっていて、Python で OAuth 2 クライアントを扱うならこの2つを組み合わせるのが最もシンプルだと思ったから。
ただし Simple ≠ Easy なので、Easy を求める人は Requests-OAuthlib あたりを使ったらいいと思う。
参考: Python の HTTP クライアントは urllib.request で十分 - Qiita
事前準備
oauthlib
は標準モジュールではないのでインストールしておく。
$ pip install oauthlib
全体を通して urllib
と json
を使うので import しておく。
import urllib
import json
認証のために必要な情報を入手しておく。
NETATMO_API_CLIENT_ID = 'xxxxxxxxxxxxxxxx'
NETATMO_API_CLIENT_SECRET = 'xxxxxxxxxxxxxxxx'
NETATMO_API_SCOPE = ['read_station']
NETATMO_API_REDIRECT_URL = 'http://localhost/callback'
今回は GET /getmeasure
API を利用したいだけなので scope は read_station
さえあればよい。
Access Token を取得する
まずは WebApplicationClient
オブジェクトを作る。
from oauthlib.oauth2 import WebApplicationClient
oauth = WebApplicationClient(NETATMO_API_CLIENT_ID)
次に、Authorization Code を取得するための URL を生成する。
url, headers, body = oauth.prepare_authorization_request('https://api.netatmo.com/oauth2/authorize', redirect_url=NETATMO_API_REDIRECT_URL, scope=NETATMO_API_SCOPE)
print(url)
ユーザにアクセス許可を求めるための URL が表示される。
Web アプリケーションであればユーザをこの URL にリダイレクトさせて、ユーザが accept すれば Authorization Code が指定した Redirect URL に飛んでくる。
ここでは仮に、Redirect URL に以下のようなパラメータ付きのアクセスが来たものとして進める。
authorization_response = 'https://localhost/callback?state=xxxxxxxx&code=xxxxxxxx'
Authorization Code が得られたので、次はこれを用いて Access Token を取得する。
url, headers, body = oauth.prepare_token_request('https://api.netatmo.com/oauth2/token', authorization_response=authorization_response, client_secret=NETATMO_API_CLIENT_SECRET)
req = urllib.request.Request(url, body.encode(), headers=headers)
with urllib.request.urlopen(req) as res:
oauth.parse_request_body_response(res.read())
oauth.prepare_token_request
では Access Token を取得するためのリクエストパラメータなどを準備してくれる。このとき authorization_response
から Authorization Code を自力で parse する必要はなく、そのまま引数で渡すだけでいい。
Netatmo API の場合はここで Client Secret を指定する必要があるが、ほとんどの API で同様だと思う。
Access Token 取得リクエストの結果はそのまま oauth.parse_request_body_response
に渡せば oauth.access_token
などに勝手に設定してくれる。
これで認証が完了した。
Access Token を使って API にアクセスする
GET /getmeasure
にアクセスしてみる。
https://dev.netatmo.com/apidocumentation/weather#getmeasure
columns = ['temperature', 'co2', 'humidity', 'pressure', 'noise']
params = {
'date_begin': 1577836800, # 2020-01-01 00:00:00 UTC
'device_id': 'xx:xx:xx:xx:xx:xx',
'scale': '30min',
'type': ','.join(columns),
'optimize': 'false',
}
url = 'https://api.netatmo.com/api/getmeasure?' + urllib.parse.urlencode(params)
url, headers, body = oauth.add_token(url)
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req) as res:
data = json.load(res)
oauth.add_token
で得られる headers
には Authorization
ヘッダが追加されている。
Access Token を更新する
Netatmo API は Access Token の有効期限が3時間と短いため、これを超える場合は Refresh Token を用いて Access Token を更新する必要がある。
url, headers, body = oauth.prepare_refresh_token_request('https://api.netatmo.com/oauth2/token', client_id=NETATMO_API_CLIENT_ID, client_secret=NETATMO_API_CLIENT_SECRET)
req = urllib.request.Request(url, body.encode(), headers=headers)
with urllib.request.urlopen(req) as res:
oauth.parse_request_body_response(res.read())
oauth.prepare_refresh_token_request
では Access Token を更新するためのリクエストパラメータなどを準備してくれる。(oauth
内部で保持している Refresh Token などを自動でリクエストパラメータとして設定してくれる)
Netatmo API の場合、ここで Client ID と Client Secret を追加で指定する必要がある。