Google Workspace におけるユーザーのアクセストークンの取得方法について（備忘録）

## 概要

![authorization-code.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407150/de3d633e-6490-7ed0-ff56-391d3866a0ef.png)

## 前提条件

### （参考）プロジェクトの API を有効にする

Google API を呼び出すアプリはすべて、API コンソールでそれらの API を 有効にする必要がある。

※ アクセストークンを取得する操作の前提条件ではないが、アクセストークンを使用した Google API の利用時に必要な前提条件である。参考までに記述する。

1. GoogleAPI コンソールで「[API ライブラリ](https://console.developers.google.com/apis/library)」を開く

1. もしプロンプトが表示されたら、プロジェクトを選択するか、新規プロジェクトを作成する

1. API ライブラリで有効にする API を選択し、[有効にする]ボタンをクリックする

1. もしプロンプトが表示されたら、請求を有効にする。

1. もしプロンプトが表示されたら、API の利用規約を読んで同意する

### 承認資格情報を作成する

OAuth2.0 を使用して Google にアクセスするアプリケーションには、Google の OAuth2.0 サーバーに対してアプリケーションを識別するための認証情報が必要である。ここではプロジェクトの資格情報を作成する方法について記述する。

本設定後、外部アプリケーションは資格情報を使用して、そのプロジェクトで有効にした API にアクセス可能となる。

1. 「[資格情報](https://console.developers.google.com/apis/credentials)」ページに移動する

1. [認証情報の作成] > [OAuth クライアント ID] をクリック

1. 「Web アプリケーション」のアプリタイプを選択する

1. フォームに必要事項を記入する

   - Web アプリケーションを使用する場合、承認された**リダイレクト URI** を指定する必要がある。リダイレクト URI は、OAuth 2.0 サーバーが応答を送信できるエンドポイントのことである。
   - テストなどでは、ローカルマシンのネットワーク（`http://localhost:8080`）などを指定することができる。なお、本記事においてはリダイレクトはすべてこのローカルネットワークのアドレスを使用する。

   ※ アプリケーションがページ上のほかのリソースに認証コードを公開しないように、[アプリの認証エンドポイントを設計する](https://developers.google.com/identity/protocols/oauth2/web-server#protectauthcode)ことが推奨されている。

認証情報を作成したら、API コンソールから client_secret.json ファイルをダウンロードし、アプリケーションだけがアクセスできる場所にファイルを安全に保存する。

> ★ 重要：**client_secret.json** ファイルを一般公開しないようにすること。また、Git などでソースコードを共有する場合は、クライアントの資格情報を誤って共有しないように、**client_secret.json** ファイルをソースツリーの外部に保存するようにすること。

### アクセス範囲を特定する

必要なリソースへのアクセスのみを設定することを推奨しており、アプリケーションほかのリソースへのアクセスが必要になった段階で、 [追加承認] プロセスを介して承認スコープへのアクセスを随時要求することを推奨している。

「[OAuth2.0 の API ドキュメント](https://developers.google.com/identity/protocols/oauth2/scopes)」には、GoogleAPI のアクセスに使用する可能性のあるスコープのリストが記述されているので、必要に応じて参照。

> Web アプリケーションが特定のユーザーデータへのアクセスを許可するスコープを使用している場合は、検証プロセスを完了が必要な場合がある。画面上に「未検証のアプリ」と表示されたアプリを検証する場合は、追加の検証要求が必要とのこと。詳細はヘルプセンターで、[未確認のアプリ](https://support.google.com/cloud/answer/7454865) 、または [アプリの確認に関するよくある質問](https://support.google.com/cloud/answer/9110914) を参照。

## OAuth2.0アクセストークンの取得

大まかな流れは以下の通り。

1. Web アプリケーションが、必要な権限を識別する

1. Web アプリケーションが、要求された権限のリストとともにユーザーを Google にリダイレクトする。

1. ユーザーが、 Web アプリケーションにアクセス許可を付与するかどうかを決定する。

1. Web アプリケーションは、ユーザーが何を決定したかを調べる。

1. 要求された権限が付与された場合、API リクエストを行うために必要なアクセストークンを取得する。

### 手順 1: 認証パラメータを設定する

まず初めに、承認リクエストを作成する。このリクエストでは、ユーザーがアプリケーションに付与するように求められるアクセス許可を定義するパラメータを設定する。

- ここでは Google OAuth 2.0 エンドポイントを直接呼び出すため、以下で説明する URL を作成し、その URL にパラメータを設定する。

#### HTTP/REST を使用する場合

Google の OAuth 2.0 エンドポイントは `https://accounts.google.com/o/oauth2/v2/auth`。このエンドポイントには、HTTPS 経由でのみアクセスが可能。HTTP 接続では拒否される。

Google 認証サーバでは、以下のクエリ文字列をサポートしている。

| パラメータ                     | 説明                                                                                                                                                                                                                                                                                                              |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| client_id（必須）              | アプリケーションのクライアント ID。この値は API コンソールの[認証情報ページ](https://console.developers.google.com/apis/credentials)にある。                                                                                                                                                                      |
| redirect_uri（必須）           | ユーザーが承認フローを完了した後に、リダイレクトする場所を指定する。値は、クライアントの API コンソール認証ページで構成した OAuth 2.0 クライアントの承認済みリダイレクト URI と完全に一致する必要がある。この値が一致しない場合は、**redirect_uri_mismatch** エラーが発生する。                                   |
| response_type（必須）          | Google OAuth 2.0 エンドポイントが認証コードを返すかどうかを決定する。パラメータ値を、Web サーバーアプリケーションのコードに設定する。                                                                                                                                                                             |
| scope（必須）                  | アクセスできるリソースを識別するスコープのリストを指定する。                                                                                                                                                                                                                                                      |
| access_type（推奨）            | ユーザーがブラウザを操作していないとき、アクセストークンを更新できるかを指定する。デフォルト値は **online**である。ユーザーがブラウザを操作していないときにアクセストークンを更新する必要がある場合は、値を **offline** に設定する。                                                                              |
| state（推奨）                  | Web アプリケーションが小児に要求と承認サーバの応答の間の状態を維持するために使用する文字列を指定する。このパラメータは、ユーザーをアプリケーション内の正しいリソースに誘導するなどのいくつかの目的で使用される。redirect_uri は推測されやすいため、本値を使用して確実性を高めることが目的。                       |
| include_granted_scopes（選択） | 追加承認機能を使用して、リソースの追加アクセスをユーザーに要求できるようにする。                                                                                                                                                                                                                                  |
| login_hint（選択）             | 認証しようとしているユーザーの一部情報を、Google 認証サーバーに提供する。これにより、Google のログインフローを簡素化することが可能。                                                                                                                                                                              |
| prompt（選択）                 | 現在のユーザー情報を提示する。このパラメータを指定しない場合、プロジェクトが最初にアクセスを要求したときにのみ、ユーザーにプロンプトが表示される。**none**：認証や同意画面などは表示させない。**consent**：ユーザーに同意を求める画面を表示する。**select_account**：アカウントを選択する用促す画面を表示させる。 |

なお、HTTP/REST を使用する方法以外にも、PHP、Python、Ruby を使用する方法も紹介されている。[ここ](https://developers.google.com/identity/protocols/oauth2/web-server#creatingclient)を参照。

### 手順 2: Google の OAuth 2.0 サーバにリダイレクトする

ユーザーを Google の OAuth 2.0 サーバにリダイレクトして、認証と承認プロセスを開始する。

#### HTTP/REST を使用した、Google 認証サーバーへのリダイレクトサンプル

以下に URL 例を示す。

```url
https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id
```

Google の OAuth 2.0 サーバーはユーザーを認証し、Web アプリケーションが、要求されたスコープにアックセスすることについてユーザーから同意を取得する。

その後、指定したリダイレクト URL を使用して、応答が Web アプリケーションに返送される。

なお、HTTP/REST を使用する方法以外にも、PHP、Python、Ruby を使用する方法も紹介されている。[ここ](https://developers.google.com/identity/protocols/oauth2/web-server#redirecting)を参照。

### 手順 3: Google 側がユーザーに同意を求める

ユーザーがアプリケーションに要求されたアクセスを許可するかを決定する。

この段階では、Google がアプリケーションの名前とユーザーの認証情報を使用してアクセスの許可を要求している Google API サービスと、許可されるアクセス範囲の概要を示す同意ウェイン同を表示する。

アプリケーション側は、アクセスが許可されたかどうかを示す Google の OAuth2.0 サーバからの応答を待つため、この段階では何もする必要はない。

### 手順 4: OAuth2.0 サーバの応答を処理する

OAuth 2.0 サーバーはリクエストで指定された URL を使用して、Web アプリケーションのアックセスリクエストに応答する。

ユーザーがアクセス要求を承認すると応答には認証コードが含まれ、要求を否認するとエラーメッセージが返却される。以下を参照。

エラー時：

```url
https://oauth2.example.com/auth?error=access_denied
```

認証コード応答時：

```url
https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
```

> ★ 重要：応答ページが HTML ページをレンダリングする場合は、そのページのすべてのリソースは URL 内の認証コードを閲覧することが可能である。そのため、任意のスクリプトで URL が読み取られ、HTTP ヘッダーの URL はすべてのリソースに送信される可能性がある。そのため、HTML ページにおいてすべてのリソースに認証資格情報を送信するかを慎重に検討する必要がある。この問題を回避するための推奨方法としては、サーバーが最初にリクエストを処理してから、レスポンスパラメータを含まない別の URL にリダイレクトすることである。

#### OAuth 2.0 サーバの応答サンプル

OAuth 2.0 サーバーの応答をテストするには、以下のサンプル URL を実行する（手順 1 と同じ URL）。なお、このサンプルでは、Google ドライブ内のファイルのメタデータを表示するためのアクセスを要求を要求する。

```url
https://accounts.google.com/o/oauth2/v2/auth？
 scope = https％3A // www.googleapis.com/auth/drive.metadata.readonly&
 access_type = offset＆
 include_granted_scopes = true＆
 response_type = code＆
 state = state_parameter_passthrough_value＆
 redirect_uri = https％3A // oauth2.example.com / code＆
 client_id = client_id
```

OAuth 2.0 フロー完了後、`http://localhost/oauth2callback` にリダイレクトする必要があり、ローカルマシンがそのアドレスでファイル（？）を提供しない限り、`404 NOT FOUND` エラーが発生する可能性がある。次以降の手順で、リダイレクトされたときに URI で返される情報について説明する。

### 手順 5: 更新トークンとアクセストークンの認証コードを交換する

Web サーバーアプリは認証コードを受信すると、それをアクセストークンと交換できるようになる。

#### HTTP/REST を使用したアクセストークンの取得方法

##### リクエスト

認証コードをアクセストークンと交換するには、`https://oauth2.googleapis.com/token` エンドポイントを呼び出し、以下のパラメータを設定する。

| Fields        | 説明                                                                                                   |
| ------------- | ------------------------------------------------------------------------------------------------------ |
| client_id     | API コンソールの資格情報ページから取得したクライアント ID                                              |
| client_secret | API コンソールの資格情報ページから取得したクライアント SECRET                                          |
| code          | 最初のリクエストから返却された認証コード                                                               |
| grant_type    | OAuth 2.0 の使用で定義されているように、このフィールドの値は `authorization_code` に設定する必要がある |
| redirect_uri  | client_id に結び付いた [API コンソール資格情報] ページにリストされているリダイレクト URI の 1 つを指定 |

- サンプルリクエストは以下。

```curl
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code
```

Google は、短期間のアクセストークンと交信トークンを含む JSON オブジェクトを返すことで、このリクエストに応答する。

※ 更新トークンとは、Web アプリが Google の認証サーバーへの最初のリクエストで access_type パラメータをオフラインに設定した場合にのみ返されるものである。

##### レスポンス

Google からのレスオンスに含まれるフィールドは以下。

|Fields|説明|
|:--|:--|
|**access_token**|Web アプリケーションが Google API リクエストを承認するために送信するトークン|
|expires_in|アクセストークンの残りの有効期間(秒単位）|
|refresh_token|新しいアクセストークンを取得するために使用できるトークン。更新トークンは、ユーザーがアクセスを取り消すまで有効。このフィールドは、Google の認証サーバーへの最初のリクエストでaccess_typeパラメーターをofflineに設定した場合にのみ表示される。|
|scope|access_token によって付与されるアクセスのスコープ|
|token_type|返却されたトークンの型。この時、本フィールドの値は常に `Beare` に設定される。|

> ★重要：Web アプリケーション側は、様々な呼び出しでアクセス可能で、長期間保管可能な場所に `access_token`（アクセストークン）と `refresh_token`（更新トークン）を保存する必要がある。更新トークンを使用すると、使用しているアクセストークンの有効期限が切れた場合に、アプリケーションで新しアクセストークンを取得することができる。そのため、アプリケーションが更新トークンを失った場合、ユーザーは OAuth 2.0 同意フローを繰り返して、アプリケーションが新しい更新トークンを取得できるようにする必要がある。

- サンプルレスポンスは以下。

```json
{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}
```

なお、HTTP/REST を使用する方法以外にも、PHP、Python、Ruby を使用する方法も紹介されている。[ここ](https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code)を参照。

## （参考）アクセストークンを使用したGoogleAPIの呼び出し

Web アプリケーションがアクセストークンを取得した後、API に必要なアクセス範囲が付与されている場合は、アクセストークンを使用して Google API を呼び出すことができる。

これを行うためには、`access_token` クエリパラメータ、または `Authorization` HTTP ヘッダー `Bearer` のいずれかを含めて、API へのリクエストにアクセストークンを含める。クエリ文字列はサーバーログに表示される傾向があるため、HTTP ヘッダーを使用することが推奨されている。

なお、以下の例における `access_token` は、実際のアクセストークンを使用すること。

### HTTP GET の例

`Authorization：Bearer` HTTPヘッダーを使用した `drive.files` エンドポイント（Drive Files API）の呼び出しは、以下のようになる。

```url
GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token
```

アクセストークンをクエリパラメータに設定した際の、API 呼び出しは以下のようになる。

```url
GET https://www.googleapis.com/drive/v2/files?access_token=access_token
```

### curl の例

これらのコマンドは、curl を使用してテスト可能で、以下のようになる。

```curl
curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files
```

または、クエリパラメータを使用した方法は、以下のようになる。

```curl
curl https://www.googleapis.com/drive/v2/files?access_token=access_token
```

## （参考）OAuth2.0の追加承認

OAuth 2.0 プロトコルでは、アプリはスコープによって識別されるリソースにアクセスするための承認を要求する仕組みである。リソースが別途必要になった時に、そのリソースに対する承認を要求することは、エスとエクスペリエンスとみなされており、Google の認証サーバもこれをサポートしている。

手順 1 のサンプルコードと、手順 2 のサンプルダイレクト URL では、すべて追加承認機能を使用している。以下のコードサンプルを使用することで、追加承認の設定をすることが可能である。

```url
GET https://accounts.google.com/o/oauth2/v2/auth?
  client_id=your_client_id&
  response_type=code&
  state=state_parameter_passthrough_value&
  scope=https%3A//www.googleapis.com/auth/drive.file&
  redirect_uri=https%3A//oauth2.example.com/code&
  prompt=consent&
  include_granted_scopes=true
```

## （参考）アクセストークンの更新（オフラインアクセス）

アクセストークンは定期的に期限切れとなり、関連する API リクエストが取得できなくなる。アクセストークンに関連付けられたスコープへのオフラインアクセスを要求した場合は、ユーザーに許可を求めるプロンプトを表示せずにアクセストークンを更新することができる。

- Google API クライアントライブラリを使用する場合、クライアントオブジェクトは、オフラインアクセス用にそのオブジェクトを構成している限り、必要に応じてアクセストークンを更新する必要がある。

- クライアントライブラリを使用していない場合は、[ユーザーを Google の OAuth 2.0 サーバにリダイレクトする](https://developers.google.com/identity/protocols/oauth2/web-server#redirecting)ときに、`access_type` HTTP クエリパラメータを `offline` にする必要がある。その場合、Google の認証サーバーは[認証コードを受け取り](https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code)、更新されたアクセストークンを返す。次に、アクセストークンの有効期限が切れた場合（またはその他の時点）、更新トークンを使用して新しいアクセストークンを取得できます。アクセストークンの有効期限が切れた場合は、更新トークンを使用して、新しいアクセストークンを取得することが可能。

オフラインアクセスとは、ユーザーがブラウザ操作をしたいないときに、 Google API にアクセスする必要があるアプリケーションの要件である（例としては、ばっくあぷサービスなど）。

### HTTP/REST を使用したアクセストークンの更新方法

アクセストークンを更新するため、Web アプリケーションは以下のパラメータを含む HTTPS `POST` リクエストを、Google の認証サーバー（`https://oauth2.googleapis.com/token`）に送信する必要がある。

#### リクエスト

|Fields|説明|
|:--|:--|
|client_id|API コンソールから取得したクライアント ID|
|client_secret|API コンソールから取得したクライアント SECRET|
|grant_type|OAuth 2.0 使用で定義されているように、このフィールドには `refresh_token` を設定する|
|refresh_token|認証コードと交換された更新トークン|

- サンプルリクエストは以下

```url
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

client_id=your_client_id&
client_secret=your_client_secret&
refresh_token=refresh_token&
grant_type=refresh_token
```

#### レスポンス

ユーザーがアプリケーションに付与されたアクセスを取り消していない限り、トークンサーバーは新しいアクセストークンを含む JSON オブジェクトを返却する。

- レスポンスリクエストは以下

```json
{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "token_type": "Bearer"
}
```

発行される更新トークンの数には制限があるので注意。クライアント/ユーザーの組み合わせごとにトークンが 1 つと、すべてのクライアントに対応する別のトークンが 1 つ存在する。更新トークンは長期間保管し、有効期間内であれば使用可能である。

## （参考）トークンを削除する

ユーザー登録を解除したり、アプリを削除したり、アプリに必要な API リソースが大幅に変更された場合に重要である。方法は 2 通りある。

### プログラムで取り消す方法

Web アプリケーションが `https://oauth2.googleapis.com/revoke` にリクエストを送信し、パラメータとしてアクセストークンを含めることで可能。

```curl
curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" https://oauth2.googleapis.com/revoke?token={token}
```

パラメータとして設定する {token} には、アクセストークン、または更新トークンをしてできる。もしアクセストークンを指定した場合に、対応する更新トークンも存在する場合は、更新トークンも取り消される。

正常にトークンがさっ駆除された場合には、HTTP レスポンスコードは `200` である。エラーの場合は、HTTP レスポンスコードは `400` である。

なお、HTTP/REST を使用する方法以外にも、PHP、Python、Ruby を使用する方法も紹介されている。[ここ](https://developers.google.com/identity/protocols/oauth2/web-server#tokenrevoke)を参照。

### アカウント設定から取り消す方法

[アカウント設定](https://myaccount.google.com/permissions) ページにて、アクセス権を取り消すことも可能。詳細については、[サポートドキュメント](https://support.google.com/accounts/answer/3466521#remove-access)を参照。

## （参考）トークンの有効期限について

付与されたトークンが機能しなくなるのは、以下の 3 点のいずれかの場合である。

- ユーザーがアプリのアクセスを取り消した場合

- トークンが 6 か月間使用されていない場合

- ユーザーアカウントに付与されたアカウント数が最大数（規定値：50）を超えた場合（この場合、古いものからトークンが無効となる）

## （参考）クライアントライブラリを使用した、OAuth2.0認証の方法（Googleからの推奨事項）

セキュリティへの影響を考えると、Google の OAuth 2.0 とのやり取りを行う際は、OAuth 2.0 ライブラリ（クライアントライブラリ）を使用することを強く推奨している。

これにより、ユーザー・サービス提供者を危機から守ることができるとある。

Web サーバーアプリケーションから、特に Google API を呼び出して操作をする場合は、以下のクライアントライブラリを使用した実装を推奨する。

### クライアントライブラリ

本記事では、以下の言語の [Google API Cliemt Libraries](https://developers.google.com/api-client-library) を使用して、OAuth 2.0 認証を行う方法について記述する。

Google API クライアントライブラリを使用してアプリケーションの OAuth 2.0 フローを処理する場合、クライアントライブラリは、アプリケーションが独自に処理する必要がある多くのアクションを担ってくれる。

以下の言語で使用が可能。

- [Go](https://github.com/googleapis/google-api-go-client)

- [Java](https://developers.google.com/api-client-library/java)

- [.NET](https://developers.google.com/api-client-library/dotnet)

- [Node.js](https://github.com/googleapis/google-api-nodejs-client)

- [PHP](https://github.com/googleapis/google-api-php-client)

- [Python](https://github.com/googleapis/google-api-python-client)

- [Ruby](https://github.com/googleapis/google-api-ruby-client)

## 参考資料

- [Using OAuth 2.0 for Web Server Applications](https://developers.google.com/identity/protocols/oauth2/web-server)

- [Obtain OAuth 2.0 -- Web server applications](https://developers.google.com/identity/protocols/oauth2#webserver)