OAuth2.0でrefresh_tokenを取得してGoogle APIにアクセス(refresh_token, access_tokenの取得まで)

技術備忘録

JavascriptでGoogle Calendar API連携を実装する際、gapi.auth2.getAuthInstance()でAPI連携認証を行うと、アクセストークンの有効期限が1時間であることから、アクセスのたびに連携認証画面へ遷移する必要があります。

ユーザビリティ向上のため、API連携認証は初回アクセス時のみ行い、サーバ側でリフレッシュトークンを管理し、ユーザのアクセスがあるごとにアクセストークンを発行するという仕様にします。

スポンサーリンク

今回の内容

  • refresh_token, access_tokenの取得

access_tokenを用いてAPIにアクセスする方法は下記を参照

OAuth2.0でrefresh_tokenを取得してGoogle APIにアクセス(access_tokenでAPIにアクセス)

スポンサーリンク

全体の流れ

スポンサーリンク

始める前に

Google APIを使用するにあたり、クライアントIDとクライアントシークレットが必要になります。取得方法についてはこちらを参考にしました。

以下の認証を行うにあたり、gapi.auth2.getAuthInstance()などでアプリ連携が認証済みだとrefresh_tokenが発行されないため、アプリ連携を解除してから行ってください。アプリ連携解除はこちらから行います。https://myaccount.google.com/permissions

スポンサーリンク

クライアント側でのAPI連携認証

// 有効なリフレッシュトークンが存在しない場合に実行
let params = {
    response_type: 'code',
    client_id: process.env.REACT_APP_CLIENT_ID,
    redirect_uri: `${location.protocol}//${location.host}/refresh_token/`, // サーバサイドで/refresh_token/にアクセスできるようにしておく
    approval_prompt: 'force',
    scope: 'https://www.googleapis.com/auth/calendar',
    access_type: 'offline'
}
let url = 'https://accounts.google.com/o/oauth2/v2/auth'
Object.keys(params).map((key, i)=>{
    url += `${i===0 ? '?' : '&'}${key}=${params[key]}` 
})
location.href = url

scopeは使用するAPIの種類に応じて適宜変更してください。

location.href = urlによってブラウザ上で認証画面に切り替わります。

params内のredirect_uriはユーザによる認証が行われた後にブラウザ上でリダイレクトされるURLです。

このURLは事前にGoogle API Console上でリダイレクトURLとして登録しておく必要があります。

リダイレクト時は以下のようにURLパラメータが付くので,サーバサイドでこれを受け取れるようにしておきます。

https://{host}/refresh_token/?code=XXXXXXXXXXXXXXXXXXXX

スポンサーリンク

サーバサイドでの処理(refresh_tokenの取得)

サーバサイドはDjangoを想定しています。

// サーバサイドで認証コードを受け取り、リフレッシュトークンを発行
import rerquests

@login_required
def refresh_token(request):
    code = request.GET.get('code', None) # URLパラメータからcodeを抽出
    if code is not None:
        # POST
        data = {
            'code': code,
            'client_id': 'client_id_xxxxxxxxxxxxxxxxxxxx',
            'client_secret': 'client_secret_xxxxxxxxxxxxxxxxxxxx',
            'redirect_uri': 'https://{host}/refresh_token',
            'grant_type': 'authorization_code',
            'access_type': 'offline',
        }
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        url = 'https://www.googleapis.com/oauth2/v4/token'
        res = requests.post(url, data=data, headers=headers)

        # refresh_tokenを取得し、データベースに保存する
        refresh_token = res.json().get('refresh_token', None)
        if refresh_token is not None:
            user = request.user
            user.refresh_token = refresh_token
            user.save()
        
    return redirect('index:index') # アプリページへリダイレクト

上記のPOSTでcodeが有効であればrefresh_tokenが取得できるはずです。

スポンサーリンク

サーバサイドでの処理(access_tokenの取得)

refresh_tokenを使用してaccess_tokenを取得します

def get_access_token(request):
    # POST
    data = {
        'refresh_token': user.refresh_token, # userに保存したrefresh_tokenを使用
        'client_id': 'client_id_xxxxxxxxxxxxxxxxxxxx',
        'client_secret': 'client_secret_xxxxxxxxxxxxxxxxxxxx',
        'redirect_uri': 'https://{host}/refresh_token',
        'grant_type': 'refresh_token',
        'access_type': 'offline',
    }
    url = 'https://www.googleapis.com/oauth2/v4/token'
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    res = requests.post(url, data=data, headers=headers)

    # access_tokenを取得し、データベースに保存する
    access_token = res.json().get('access_token', None)
    if access_token is not None:
        user = request.user
        user.access_token = access_token
        user.save()
        return access_token

    return ''
スポンサーリンク

access_tokenの検証

取得したaccess_tokenが有効か検証することもできます

def validate_access_token(access_token):
    url = 'https://www.googleapis.com/oauth2/v3/tokeninfo'
    res = requests.get(url, {'access_token': access_token})
    if res.json().get('error_description', None) is None:
        return True # valid
    return False # invalid

次のようなJSONが返されます

// access_tokenが有効な時
{
  "azp": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
  "aud": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
  "scope": "https://www.googleapis.com/auth/calendar",
  "exp": "1234567890",
  "expires_in": "3554", // 残り有効時間(秒)
  "access_type": "offline"
}

// access_tokenが無効な時
{
  "error_description": "Invalid Value"
}

取得したaccess_tokenを使用してAPIにアクセスする方法は次のページで説明します。

OAuth2.0でrefresh_tokenを取得してGoogle APIにアクセス(access_tokenでAPIにアクセス)

参考ページ

コメント

タイトルとURLをコピーしました