RORO

ふつうの日記

Python用のGoogle API / GCPライブラリの状況 (2019年末)

ここ数年でPython用ライブラリが少し整理されたようで、ちまたの記事は現在の状況に合っていないものが多い。最新っぽいやり方を整理しておく。

最後にGoogle PhotosのAPI (Photos Library API) を呼んでみたので、それについても末尾に書いておく。

oauth2clientはDeprecated

Web上ではoauth2clientを使っている記事がたくさん見つかるが、これは既にdeprecatedになっている。現在は以下のようになっている。

  • Service Accountの認証や、Googleのトークンの扱いは、google-authで実装されている。
  • OAuth 2.0のフローを行う必要があるときはサードパーティ製のoauthlibなどを使う(google-auth-oauthlibというヘルパも用意されている)。

ライブラリの構成

GCP用も含めて、ほとんどのライブラリはここにある:

以下は(ほぼ)関係ない:

Google Cloud Platform (GCP) 関係

GCPの各サービスごとにパッケージgoogle-cloud-*が用意されている (例えば google-cloud-storageなど) 。ちなみに、かつて存在したgoogle-cloudというメタパッケージは、既にdeprecatedで空っぽになっている。

これらは以下のような綺麗な名前空間に収まっている。

import google.cloud.speech

各サービスで共通の部分はgoogle-api-core, google-cloud-core, google-resumable-mediaなどのパッケージとして抽出されている。これらは必要に応じて依存パッケージとしてインストールされるのであまり気にしなくていい。

Google’s Discovery-based API

google-api-python-client - これはGoogleのサービス(Google Driveなど)のAPIを叩くための汎用ライブラリ。API定義をネットから取ってきて、APIを表現するオブジェクトを手元で動的に組みたてる仕組みになっている。

import googleapiclient

ただしGCPを扱うときはこれを使うべきではない。「GCPについてはアクティブに開発されているGCP用のライブラリを使え」とのこと。

google-auth

認証周りを抜き出したもの。Service Accountの認証のほか、トークンのverifyなどもこれでできる。google-cloud-*google-api-python-clientはこれに依存している。

google-auth:

google-authには、ユーザクレデンシャルを取得する(=OAuth 2.0のフローを助ける)機能がない(oauth2clientにはあった)。アクセストークンを取得したければ、oauthlibなどをそのまま使うか、Googleが用意しているヘルパーgoogle-auth-oauthlibを使う。

(もちろん、Webフロントエンドなどがある場合はブラウザ上でGoogle Sign-Inなどを使ってアクセストークンを取得すればいいので、サーバ側はトークンの検証だけすればいい。)

google-auth-oauthlib:

認証方法

これはPython特有ではないけど…

Google Cloud Platformの認証の種類は以下の通り:

  • Service Account - server-to-serverの通信には基本的にこれを使う。OAuth 2.0に基づいている(がOAuth 2.0そのものではない?)。
  • OAuth 2 - ふつうのOAuth 2.0のフロー。ユーザの同意を得て、ユーザのデータにアクセスするためのトークンを取得するときに使う。
  • API Key - APIキーによる認証。一部のAPIを使うときに必要。

Service Account

推奨される方法: クレデンシャルファイルを利用する。環境変数 GOOGLE_APPLICATION_CREDENTIALS でクレデンシャルのjsonファイルのパスを指定しておけば、あとはライブラリが裏で勝手に認証を行ってくれる。

上記の通り、通常はライブラリに任せればいいのだけど、内部的には次のようなことをしている → クライアントの秘密鍵で要求用のJWTを署名して、それをエンドポイントに送信してアクセストークンを取得し、そのトークンでAPIを呼ぶ。(Pythonだと、google/auth/service_accounts.pyrefresh()あたりを追うとわかる)。

JWTの署名アルゴリズムにはRS256(256bit RSA暗号)が使われる。一部のAPIでは、上記のJWTそのものをそのままアクセストークンとして使うこともできる。

OAuth 2.0

Googleが提供しているGoogle Sign-In (Web (JS), Android, iOS, TV, etc.) などの認証ライブラリが使える場合はそれを使えばアクセストークンを取得できる。認証時に必要なスコープを要求すればいい。

上記で対応できない場合は、PlainなOAuth 2.0を使う(デスクトップアプリ、CLIツールなど)。

Pythonの場合は、PlainなOAuth 2.0フローを簡便に行うためのgoogle-auth-oauthlibパッケージも用意されている。

実際にやってみる。

google-cloud-*のほうは分かりにくいことは特にないので触れない。ここではgoogle-api-python-clientを使ってみる。

コマンドラインから自分のアカウントのGoogle Photosの写真を列挙してみることにした。

事前準備として、Google Cloud Consoleで適当なOAuth 2のクライアントIDを作っておく必要がある。

そして、コード自体は以下だけでOK。短い。

from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build

# Obtain an access token
flow = InstalledAppFlow.from_client_secrets_file(
    'client_id.json',
    scopes=['https://www.googleapis.com/auth/photoslibrary.readonly'])
credentials = flow.run_local_server()

# Call the Photos Library API
photos_service = build('photoslibrary', 'v1', credentials=credentials)
result = photos_service.mediaItems().list().execute()
print(result['mediaItems'])

実行するとブラウザが開いてGoogleの認証ページが表示される。デスクトップアプリやCLIのツールでアクセストークンを受け取るためのトリックとして、ローカルにWebサーバを立ててそこをOAuthフローのリダイレクト先にする、ということを行うのだが、その一連の処理はgoogle_auth_oauthlibInstalledAppFlowがすべてやってくれる。