🌏

OAuth2認証が必要なGoogle Cloud APIをプログラムから実行する

2024/12/12に公開

はじめに

Google Cloud APIは、様々なGoogleの機能をHTTPで操作する為のAPI群です。

https://cloud.google.com/apis/docs/overview?hl=ja

認証方式には、APIキー方式やサービスアカウントキー方式などがありますが、ユーザーのデータにアクセスするAPIや、ユーザーの代わりに操作を行うAPIなどでは、OAuth2.0認証が必要です。

具体的には、Google Drive APIや、Google Calendar API、Google Analytics API等の利用時には、Googleサインイン画面を表示して、ユーザーの認証と使用する機能に対する同意が必要になります。

セキュリティの面からは必要な認証機能なのですが、プロジェクト単位で作成したGoogle Driveなどに、プログラムからアクセスするような場合には、この認証フローの為に、自動実行することができなくなってしまいます。

このような場合の対応方法について説明します。

Google Forms API

先日、Google Formsを使用してアンケートを作成することがありました。
その際、Backend側で、アンケート情報を収集する機能が必要だったので、Google Forms APIを使用して、収集されたアンケート内容を取得するプログラムを作成しました。

https://developers.google.com/forms/api/reference/rest?hl=ja

Google Formsで作成したアンケートの回答は、Google Drive上に保存されます。
通常は、プロジェクトで作成されたGoogleアカウントのGoogle Drive上に保存されると思います。

そのアンケートの回答を取得するには、forms.responses.list APIを叩く必要があるのですが、このAPIにアクセスする為には、Google DriveのOAuthスコープが必要なので、Googleサインイン画面を表示して、ユーザ認証と権限付与の同意が必要です。

https://developers.google.com/forms/api/reference/rest/v1/forms.responses/list?hl=ja

必要になる権限スコープは以下の3つです。

このAPIを、Backendのプログラムで実行させるための準備を行っていきます。

Google Cloud Platformコンソールでの準備

Google Cloud APIを使用するには、Google Cloud Platformでプロジェクトの作成が必要です。

https://console.cloud.google.com/

上記コンソールにGoogleアカウントでログインし、プロジェクトを作成してください。

Google Forms APIの有効化

まずは、Google Forms APIを有効にします。

Google Cloud Platformコンソールにログインしたら、クイックアクセスにある「APIとサービス」をクリックし、「APIとサービスを有効にする」ボタンを押します。

検索窓に「forms」と入力し、表示されるGoogle Forms APIを選択して、「有効にする」ボタンを押すと、APIが有効になります。

認証情報の作成

次に、左メニューから「認証情報」を選択し、「認証情報を作成」ボタンを押します。

表示される「OAuthクライアントIDの作成」画面で、以下のように入力します。

  • アプリケーションの種類:ウェブアプリケーション
  • 名前:(適当な名称)
  • 承認済みのリダイレクトURL:http://localhost:8080(アクセスできなくてOK)

クライアントIDを作成したら、一覧から選択して詳細を表示させ、「クライアントID」と「クライアントシークレット」をメモしておきます。

最後に、認証を行うユーザのGoogleアカウントのメールアドレスをテストユーザに追加します。

リフレッシュトークンの取得

Backendプログラムで、Google Forms APIを利用するには、以下の3つが必要です。

  • クライアントID(作成済み)
  • クライアントシークレット(作成済み)
  • リフレッシュトークン

上記3つの情報があれば、プログラムから、APIにアクセスする為のアクセストークンを取得して、APIにアクセスすることができます。

クライアントIDとクライアントシークレットは、すでに作成済みなので、リフレッシュトークンを取得します。

codeの取得

リフレッシュトークンを取得する為に、まず、codeパラメータを取得します。

ブラウザで「https://accounts.google.com/o/oauth2/auth」 に以下の値をパラメータに追加して実行してください。

name value
client_id クライアントID
redirect_uri 認証情報作成で入力したリダイレクトURL
(http://localhost:8080)
scope 取得する権限スコープ
複数の場合はスペースを入れて記述
今回はGoogle Forms APIのlistで必要な下記の3つのスコープを指定
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/forms.responses.readonly
response_type code
access_type offline

以下のようなURLを作成してブラウザでアクセスします。

権限スコープの一覧はこちらに載っています。
また、使用するAPIのヘルプページにも必要なスコープの記載があります。
https://developers.google.com/identity/protocols/oauth2/scopes?hl=ja

生成したURLに、ブラウザでアクセスすると、Googleアカウントのサインイン画面が表示されますので、サインインします。

テスト環境だと、以下のようなページが表示されますが、気にせず「続行」を選択します。

権限許可のページが表示されますので、すべての権限にチェックを入れます。

ページ遷移すると、設定したRedirectUrl(hrrp://localhost:8080)に遷移しますが、アクセスできないのでエラーになります。

この時、アドレスバーに表示されているURLに、「code」パラメータが表示されていますので、これをコピーします。

リフレッシュトークンの取得

取得したcodeパラメータを指定して、リフレッシュトークンを取得します。
https://www.googleapis.com/oauth2/v4/token」 にPOSTでQueryParameterとして、以下のデータを送信します。

name value
code 取得したcodeの値
client_id クライアントID
client_secret クライアントシークレット
redirect_uri 認証情報作成で入力したリダイレクトURL
(http://localhost:8080)
scope 取得する権限スコープ
複数の場合はスペースを入れて記述
今回はGoogle Forms APIのlistで必要な下記の3つのスコープを指定
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/forms.responses.readonly
grant_type authorization_code

curlで実行する場合は、以下のようになります。

curlで実行
curl -XPOST https://www.googleapis.com/oauth2/v4/token \
--data "code=[codeの値]&client_id=[クライアントID]&client_secret=[クライアントシークレット]&redirect_uri=http://localhost:8080&scope=https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/forms.body.readonly https://www.googleapis.com/auth/forms.responses.readonly&grant_type=authorization_code"

成功すると、以下のようなJSON形式のレスポンスが取得できます。

レスポンスデータ
{
"access_token": "XXXXX",
"expires_in": 3599,
"refresh_token": "XXXXXX",
"scope": "https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/forms.responses.readonly https://www.googleapis.com/auth/forms.body.readonly",
"token_type": "Bearer"
}

これでリフレッシュトークンが取得できました。

このリフレッシュトークンは、再度上記の手順でGoogleサインインを行うと無効になってしまいますので、その場合はcodeの取得からやり直してください。

Google Forms APIの実行

それでは、取得したクライアントID/クライアントシークレット/リフレッシュトークンを使用して、Google Forms APIを実行してみます。

実際にプログラムで実行する場合は、クライアントID/クライアントシークレット/リフレッシュトークンを引数にして、プログラム内部で以下の2つの処理を実行することになります。

  1. アクセストークンの取得
  2. APIの実行

アクセストークンの取得

APIを実行する為に、まずアクセストークンを取得します。

https://www.googleapis.com/oauth2/v4/token」 にPOSTでQueryParameterとして、以下のデータを送信します。

name value
client_id クライアントID
client_secret クライアントシークレット
refresh_token リフレッシュトークン
grant_type refresh_token

curlで実行する場合は、以下のようになります。

curlで実行
curl -XPOST https://www.googleapis.com/oauth2/v4/token \
--data "client_id=[クライアントID]&client_secret=[クライアントシークレット]&refresh_token=[リフレッシュトークン]&grant_type=refresh_token"

成功すると、以下のようなJSON形式のレスポンスが取得できます。

レスポンスデータ
{
"access_token": "XXXXX",
"expires_in": 3599,
"refresh_token": "XXXXXX",
"scope": "https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/forms.responses.readonly https://www.googleapis.com/auth/forms.body.readonly",
"token_type": "Bearer"
}

取得したaccess_tokenを、API実行時のHTTP Headerに、Authorization: Bearer XXXXXX の形で設定してリスエストを送信します。

ちなみに、取得したアクセストークンには有効期限があります。

レスポンスのexpires_inが有効期限(秒)の情報になりますので、この時間が過ぎたら再度アクセストークンを取得する必要があります。

APIの実行

Google Formsで作成したアンケート回答を取得するには、forms.responses.listを使用します。

https://developers.google.com/forms/api/reference/rest/v1/forms.responses/list?hl=ja

このAPIでは、以下のURLにHTTP GETでアクセスすると、回答内容がJSON形式で取得できます。

このリクエストのHTTPヘッダーに、先程取得したアクセストークンを設定します。

curlで実行する場合は、以下のようになります。

curlで実行
curl https://forms.googleapis.com/v1/forms/[フォームID]/responses \
  -H "Authorization: Bearer [アクセストークン]"

成功すると、以下のような回答データが返却されます。

レスポンス
{
  "responses": [
    {
      "responseId": "XXXXX",
      "createTime": "2024-11-07T04:17:48.544Z",
      "lastSubmittedTime": "2024-11-07T04:17:48.544044Z",
      "answers": {
        "0ed7f87c": {
          "questionId": "0ed7f87c",
          "textAnswers": {
            "answers": [
              {
                "value": "2F"
              }
            ]
          }
        },
        "715c81b0": {
          "questionId": "715c81b0",
          "textAnswers": {
            "answers": [
              {
                "value": "選択肢 1"
              }
            ]
          }
        }
      }
    },
    {
      "responseId": "XXXXX",
      "createTime": "2024-11-07T04:18:07.078Z",
      "lastSubmittedTime": "2024-11-07T04:18:07.078451Z",
      "answers": {
        :
        :
        :

Discussion