722 文字
4 分
Google APIのOAuth2に関連したトークンの扱い方法とシーケンス
概要
- Using OAuth 2.0 to Access Google APIsにシーケンスがかいてあります。

- 上記のシーケンスはシンプルすぎて、重要なシーケンスとアクターが漏れているので、もう少し細かくシーケンス図を書き直しました。
- 特に、
refresh tokenの取得方法と、取得タイミング、保存タイミングなどの情報がアプリケーション開発者がアプリケーションを設計する上で重要なのですが、オフィシャルドキュメントでは網羅されていませんでした。
シーケンス図

用語の整理
authorization code- 認証コード
- これを元に、
refresh tokenとaccess tokenを交換する。取得したらauthorization codeは無効になる。 - ユーザが承認した直後にしか使わない。
- expireする。Googleでは時間の記載は無いけど、Facebookでは10分。
- 4番のシーケンスにおける、
codeパラメータで取得出来る。。
access token- API呼び出しに使うトークン。
- レスポンスを見ていると、Googleでは3600秒(=60分)でexpireするトークンが発行されている。
refresh token- 基本的には、アプリケーション側で永続化しておく。
- expireはしない。ユーザ側でrevokeできる。
- 無効になってしまったら
authorization codeから生成する必要がある。そのために、ユーザに再び承認をもらう必要がある。この時点ではauthorization codeは存在していないはずなので。 - 大事に保存しておく必要がある。このcredentialとアプリ情報が第三者に漏れると、権限を乱用出来てしまう。
- 漏れた場合は、Googleに登録したアプリをのcredentialをリセットする必要があるので、他のユーザにも影響するため厳重に管理する必要がある。
メモ
- expirationやトークンのライフサイクルに関してはこの辺りが情報ソース。
- authorization tokenを再発行するためには、自分のGoogleのSecurity&Privacyページに手アプリの認証をrevokeする必要がある。
- そうじゃないと、新しいaccess_tokenが発行されるだけで、認証情報はリセットされない。
- アプリ側で生成する認証ページのURLのパラメータを変更したときには、revokeしなければ、前回と同じパラメータの認証情報のままaccess tokenなどが生成されてしまうので注意。
ソースコード
- rubyのコードで主要なコードスニペットを書いておきます。
- わかりやすいように値の例も書いておきます。
refresh tokenを取得できる、authorization codeを取得するコード。
client = Signet::OAuth2::Client.new({ client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'), client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'), authorization_uri: 'https://accounts.google.com/o/oauth2/auth', scope: [Google::Apis::GmailV1::AUTH_GMAIL_READONLY, 'email'], redirect_uri: 'http://localhost:3000/callback', access_type: 'offline', # need this to get refresh_token.})
# ex:# http://localhost:3000/callback?code=4/nQCxXval2Q8tfg0StBx81vcILZU7kEp9BMkGq27geFsSJU3fOQ8c_dMz5VW_hySmXVq0BWtJ_lopkUk66u8ZoCx&scope=openid+email+https://www.googleapis.com/auth/plus.me+https://www.googleapis.com/auth/gmail.readonly+https://www.googleapis.com/auth/userinfo.emailclient.authorization_uri.to_sauthorization codeからrefresh tokenとaccess tokenを取得するコード。
client = Signet::OAuth2::Client.new({ client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'), client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'), token_credential_uri: 'https://oauth2.googleapis.com/token',})
client.code = "[authorization code]"access_token_hash = client.fetch_access_token!
# ex:# ya29.GltcBh5BsH71zSz3HI_NCTTyn2W5gfn3eVUXoQU3sHkMxF-Tu3x1gL3mZSNFM_HIglSz8oKiVj-vgFB1td-UzdXaKbutynonpws-dsG4l1mnudwFiZv9Dku8Hb-Xaccess_token_hash['access_token']
# ex:# 1/L8qZrV5S88vOmRd9WVWxAmv4c8QJB9lMf9mqnfkZkVkaccess_token_hash['refresh_token']refresh tokenを使って、access tokenを取得する。
client = Signet::OAuth2::Client.new({ client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'), client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'), token_credential_uri: 'https://oauth2.googleapis.com/token',})
client.refresh_token = '[refresh_token]'access_token_hash = client.fetch_access_token!
# ex:# ya29.GltcBhsO9iH4fWJITG3chjNrki5vk0M1I-bFcjTsHW2Ln4CBRZjT-eGBSlf_Qa4MewfWxsrU_s-DMb4AwOrkFpgUuGegStiGKKZkiazoPU5c3JUihNzOTcdJeKKXaccess_token_hash['access_token'] Google APIのOAuth2に関連したトークンの扱い方法とシーケンス
https://blog.teraren.com/posts/google-api-oauth2-sequence/