oauth2client でリフレッシュトークンが取得できない
Google Spreadsheet などのサービスの API とやりとりする Google App Engine(GAE)アプリを比較的多く手がけているが、その際に利用するのが OAuth2 という認証プロトコルである。スマホアプリなどで「このアプリケーションが次の機能へのアクセスを求めています」云々というページが表示されることがあるが、あれこそがこの OAuth2(バージョン1かもしれないが)による認証フローである。ひとまずここでは OAuth2 自体の仕組みについては説明しない。
GAE で OAuth2 を利用するには、oauth2client というライブラリを使うのが一般的である。パッケージ内に appengine.py というそのものずばりのファイルがあり、ツイートに書いた OAuth2DecoratorFromClientSecrets
というクラスもここに書かれている。そして、以下のようなサンプルも記されている。
decorator = OAuth2DecoratorFromClientSecrets(
os.path.join(os.path.dirname(__file__), 'client_secrets.json')
scope='https://www.googleapis.com/auth/plus')
class MainHandler(webapp.RequestHandler):
@decorator.oauth_required
def get(self):
http = decorator.http()
# http is authorized with the user's Credentials and can be
# used in API calls
このサンプルの MainHandler に割り当てられている URL に最初にアクセスすると、例の「このアプリケーションが次の機能への……」というページにリダイレクトされ、スコープで指定された外部サービス(上記の場合は Google+ の API)とやりとりするための鍵みたいなもの(=アクセストークン)が発行される。認証フローが済んでいれば、次にアクセスしたときにはリダイレクトはされず、取得済みのアクセストークンを使って外部サービスとのやりとりがスムーズに行なえるようになる……のだが、アクセストークンには有効期限があるため、一定時間が経過すると再びアクセストークンを取得しようとする。
しかしながら、OAuth2 にはリフレッシュという仕組みがあり、アクセストークンと同時に取得したリフレッシュトークンを使えば、無駄なリダイレクトなどが挟まれることなく新しいアクセストークンを取得できる……はずなのだが、どうも上記サンプルのままだとリフレッシュトークンが取得できないのだ。
その理由はツイートに書いたとおりだが、上記サンプルを例にとれば、decorator への代入部分を以下のように変更する必要がある。
decorator = OAuth2DecoratorFromClientSecrets(
os.path.join(os.path.dirname(__file__), 'client_secrets.json')
scope='https://www.googleapis.com/auth/plus',
access_type='offline',
prompt='consent')