Google+ API使ってるところ直せと言われたので対応した話

# はじめに

本日（2018/12/21）こんなメールが来ました。

![Google+_APIs_being_shutdown.png](https://qiita-image-store.s3.amazonaws.com/0/141091/ab88e052-71de-314e-73a6-4ff14e2567fe.png)

え？使ってないよと思ったのですが「お前のプロジェクトで最近呼び出ししてるのこれな」と出ているのでどこで使っているのか確認＆対処しました。

# django-googleauth

このDjangoアプリ（Google+ API使ってるから直せと言われているプロジェクト）はユーザ管理にGoogle認証を使っているのですが、ライブラリは当時（2015年4月）に見つけてきた[django-googleauth](https://github.com/jcarbaugh/django-googleauth)というものを使っています[^1]。コードは非常にシンプル（必要最小限）なのですぐに読めます。

[^1]: 一番初めはdjango-openid-authというライブラリを使っていたのですが、OpenID 2.0が廃止されたのでこれに変えたという経緯もあります。

で、[views.py](https://github.com/jcarbaugh/django-googleauth/blob/master/googleauth/views.py)を見てみたところ、

```py:googleauth/views.py抜粋
GOOGLE_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth'
GOOGLE_TOKEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token'
GOOGLE_USERINFO_ENDPOINT = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect'
```

あー。

なおこのエンドポイントにアクセスして何しているかというと苗字と名前取っているだけです。

```py:googleauth/views.py抜粋
def callback(request):
    省略

    # get profile data

    if GET_PROFILE:

        headers = {'Authorization': 'Bearer %s' % attributes['access_token']}
        resp = requests.get(GOOGLE_USERINFO_ENDPOINT, headers=headers)

        if resp.status_code == 200:

            profile = resp.json()

            attributes['first_name'] = profile.get('given_name')
            attributes['last_name'] = profile.get('family_name')
```

# Google Sign-inでの方法

Googleから来ているメールによると「people.get使ってるのならGoogle Sign-inのやつを使うようにすればいい」と書いてあったので[Google Sign-inのページ](https://developers.google.com/identity/)を確認。ページ末尾に[OpenID Connectについての追加情報ページ](https://developers.google.com/identity/protocols/OpenIDConnect#obtaininguserprofileinformation)へのリンクがあったのでそっちに飛ぶ。

つまり、

1. エンドポイントなどの情報が書かれたJSON（ディスカバリードキュメント）を取得。このURIはハードコードしていい。
2. 取得したJSONからuserinfoのエンドポイントを取り出す。
3. 取り出したエンドポイントに認証情報付きでアクセスして必要な情報を取得する。

とすればよいということになります。
で、そのように修正。まあディスカバリードキュメントが取れないことないやろとステータスチェック省いていますが良い子は真似してはいけません。

```py:googleauth/views.py修正版
    if GET_PROFILE:

        # first, get user info endpoint
        resp = requests.get('https://accounts.google.com/.well-known/openid-configuration')
        userinfo_endpoint = resp.json().get('userinfo_endpoint')

        headers = {'Authorization': 'Bearer %s' % attributes['access_token']}
        #resp = requests.get(GOOGLE_USERINFO_ENDPOINT, headers=headers)
        resp = requests.get(userinfo_endpoint, headers=headers)

        if resp.status_code == 200:

            profile = resp.json()

            attributes['first_name'] = profile.get('given_name')
            attributes['last_name'] = profile.get('family_name')
```

Google+ APIを無効化し、ちゃんと苗字と名前が取れることを確認。

# あとがき

というわけで知らずに使っていたGoogle+ APIへの対応内容を書きました。
django-googleauthにプルリク投げようかなと思ったのですがもうメンテされてないっぽいので投げてません。

で、これがやや大事な話ですが、最近だとGoogle含めた[social-auth-app-django](https://github.com/python-social-auth/social-app-django)がよく使われているみたいですね。2018/12/21時点だとこちらも[Google+のエンドポイントがハードコーディングされています](https://github.com/python-social-auth/social-core/blob/2.0.0/social_core/backends/google_openidconnect.py)。social-auth-app-djangoはガワで本体はsocial-auth-core（パッケージ名はsocial_core）なので注意。まあこちらは活発に開発されているようなのでそのうち対応されると思いますが。

# 余談

OAuthだとかOpenIDに関して詳細に、「ガチに」解説した本ってあるのですかね（紙媒体がいい人）。ここら辺の技術を興亡含めてがっつり学びたいと思っているのですが。