Googleカレンダーのサーバーサイド用トークンをgoogle-authとoauthlibを使って取得する
Googleカレンダーの情報をサーバーサイドで取得したい場合、Googleカレンダーのaccess_tokenとrefresh_tokenが必要になります。これを取得するには、ユーザーにGoogleアカウントでの認証を求める必要があります。
iOS/AndroidアプリでGoogleアカウントの認証を取る場合、アプリ側でauth_codeを取得し、それをサーバーサイドに送信し、サーバーサイド側でauth_codeを使ってGoogleカレンダーのaccess_tokenとrefresh_tokenと交換することになります。
公式のリファレンスはこちらやこちらですが、サーバーサイド側のPythonコードで使われているoauth2clientはすでに非推奨になっています。 そのため、代わりに利用が推奨されている google-auth と oauthlib にサンプルコードを書き換える必要があります。
にも関わらず、アプリで取得した auth_code をサーバーサイドで access_token と refresh_token に交換するコードが公式ドキュメントどころかいくら探せど見つからず、めっちゃ苦労しました。 ので、ちゃんと動いたコードを載せます。
from google_auth_oauthlib.flow import Flow
flow = Flow.from_client_secrets_file(
'/path/to/client_secret.json',
scopes=[
'openid',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/calendar'
]
)
# クライアントで取得したauth_codeを渡す
credentials = flow.fetch_token(code=auth_code)
print(credentials.get('access_token'))
print(credentials.get('refresh_token'))
print(credentials.get('id_token'))
google_auth_oauthlibのFlowを使います。Googleコンソールから取得できるclient_secret.jsonを適当な場所において、そのパスを第一引数、認証のスコープを第二引数に渡します。このとき、第二引数のスコープはアプリでauth_codeを取得するときのスコープと一致させてください。
あとは、flow.fetch_token(code=auth_code)
すれば、dictが帰ってくるのでそれぞれ、.get('access_token')
、.get('refresh_token')
でGoogleカレンダーにアクセスするためのトークンを取得できます。
id_tokenについては詳しい説明を割愛しますが、これを使ってemailやnameを取得します。
from google.oauth2 import id_token
from google.auth.transport.requests import Request
decoded_token = id_token.verify_oauth2_token(
credentials.get('id_token'),
Request(),
'YOUR_GOOGLE_OAUTH2_CLIENT_ID'
)
if decoded_token.get('iss') not in ['accounts.google.com', 'https://accounts.google.com']:
raise ValueError('Invalid oauth issuer.')
print(decoded_token.get('email'))
print(decoded_token.get('name'))
普通にありそうな状況なのに、日本語も英語も情報が少なくてかなり苦労しました。英語の公式ドキュメントも未だに非推奨のoauth2clientなので、oauth2clientが使われていることが多いのかもしれません。
Discussion