LoginSignup
49
41

More than 3 years have passed since last update.

Python でシンプルに OAuth 2 する (urllib + oauthlib)

Last updated at Posted at 2020-01-03

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

全体を通して urllibjson を使うので 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 を追加で指定する必要がある。

49
41
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
41