Help us understand the problem. What is going on with this article?

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

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 を追加で指定する必要がある。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away