[GCP]継続的にAPIを利用するための、リフレッシュトークンを用いたアクセストークンの取得方法

# はじめに
アクセストークンは1時間ほどで有効期限が切れてしまうため、継続的にAPIを利用するためには定期的にアクセストークンを更新する必要があります。
GUIの場合だと以下のURLから手動で更新が可能ですが、この方法だと自作アプリに組み込めません。
https://developers.google.com/oauthplayground/

そこでcurlコマンドが利用できる、リフレッシュトークンを用いたアクセストークンの取得方法をまとめました。

# 手順
## 1. OAuth 2.0 クライアント ID の作成
まずOAuth 2.0 クライアント IDを作成する必要があります。

### 認証情報画面を開く
GCPにログイン後、APIとサービス -> 認証情報 を選択すると認証情報画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/8ee6d262-abb2-7fcf-5f7f-41e14ab29ce0.png)

### OAuth クライアント ID選択
認証情報を作成を選択し、OAuth クライアント IDを選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/a3136fdc-465d-c929-f0c7-104896c337a8.png)

### 同意画面を設定を選択
画面右側の同意画面を設定を選択してください。
（過去に設定済みの方はこの項目を省略できます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/c7bc490c-fa5c-5e9f-6724-bf80173a533a.png)

その後表示される画面でアプリケーション名を入力し、「保存」を選択します。
その他の項目は入力しなくても構いません。

### 名前の入力
「その他」を選択し、適当な名前を入力し「作成」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/f63ff5c4-3d62-a572-d2df-9147cad52f26.png)

### OAuth クライアント IDが作成される
以下の画面が表示されたらOKを選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/42d8937d-19f7-3bb0-a175-22f2d0ee2c49.png)

これでOAuth 2.0 クライアントIDが作成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/16967aaa-905e-30e4-1608-1c2e304c981d.png)

## 2. クライアントIDとクライアントシークレットの確認
先ほど作成したOAuth クライアント IDの、クライアントIDとクライアントシークレットを確認します。
（認証情報画面に表示されるOAuth クライアント IDの名前を入力すると以下の画面が表示されます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/a74d5ced-2731-ccbc-8c3e-3bdfe13f8e2a.png)

## 3. スコープの確認
スコープとはアクセスするAPI名と同じような意味です。
本当は https://developers.google.com/identity/protocols/googlescopes からスコープを探すのが正しいと思いますが見つけづらいため、以下のサイトから探すこととします。
https://developers.google.com/oauthplayground/

今回はCloud Strageへ継続的にファイルをアップロードしようと思うので、Cloud Strageのread_writeと書かれている `https://www.googleapis.com/auth/devstorage.read_write` を利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/a9810d06-3ec4-8ed1-6d8f-3da60c90aacf.png)

## 4. Authorization codeの取得
以下の[クライアントID]と[スコープ]の部分に、これまでの手順で取得できたクライアントIDとスコープを入力します。

```
https://accounts.google.com/o/oauth2/auth?
  client_id=[クライアントID]&
  redirect_uri=http://localhost&
  scope=[スコープ]&
  response_type=code&
  access_type=offline
```

このURLを1行にしてブラウザに貼り付けてアクセスすると、アカウントの選択画面に繊維しますので、適当なアカウントを選択します。その後表示される画面で「許可」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/92462e8c-3542-a690-a0b3-0236e8af620f.png)

すると以下の画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402872/4414f8b6-31f6-3060-54dc-2dccb271e42d.png)

この画面が表示されている時のURLを確認すると以下のようになっています。
この「XXXXXXXX」の部分がAuthorization codeです。

http://localhost/?code=XXXXXXXX&scope=https://www.googleapis.com/auth/devstorage.read_write

## 5. curlを用いたアクセストークンとリフレッシュトークンの取得
以下の[Authorization code]、[クライアントID]、[クライアントシークレット]に入力して、コマンドを実行してください。
このコマンドは1回のみ実行可能で2回目以降はエラーが返ってきます。もし再実行したい場合は「4. Authorization codeの取得」の手順から実行する必要があります。

```
curl -XPOST https://www.googleapis.com/oauth2/v4/token --data "code=[Authorization code]&redirect_uri=http://localhost&client_id=[クライアントID]&client_secret=[クライアントシークレット]&scope=&grant_type=authorization_code"
```

すると以下の結果が得られます。
ここにアクセストークンとリフレッシュトークンの情報が記載されています。

```json
{
  "access_token": "アクセストークン",
  "expires_in": 3600,
  "refresh_token": "リフレッシュトークン",
  "scope": "https://www.googleapis.com/auth/devstorage.read_write",
  "token_type": "Bearer"
}
```

取得したアクセストークンでCloud Strageにファイルがアップロードできるか試す場合は以下にコマンドを実行してください。
（ https://cloud.google.com/storage/docs/uploading-objects?hl=ja ）

```
curl -X POST --data-binary @[OBJECT] \
    -H "Authorization: Bearer [OAUTH2_TOKEN]" \
    -H "Content-Type: [OBJECT_CONTENT_TYPE]" \
    "https://www.googleapis.com/upload/storage/v1/b/[BUCKET_NAME]/o?uploadType=media&name=[OBJECT_NAME]"
```

入力する内容は以下の通りです。
1つのアクセストークンで基本的には全てのバケットにアップロード可能です。

|変数名|入力する内容|
|:----------|:-----------|
|[OBJECT]|アップロードしたいファイル名|
|[OAUTH2_TOKEN]|先ほど入手したアクセストークン|
|[OBJECT_CONTENT_TYPE]|コンテントタイプ（テキストならtext/plain、zipならapplication/zipなど）|
|[BUCKET_NAME]|バケット名|
|[OBJECT_NAME]|バケットに保存したあとのファイル名（OBJECTと異なる名前でも同じ名前でもよい）|

## 6. curlを用いたアクセストークンのリフレッシュ
以下の[クライアントシークレット]、[リフレッシュトークン]、[クライアントID]、に入力して、コマンドを実行してください。

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

すると以下の結果が得られます。
ここに新しいアクセストークンの情報が記載されています。

```json
{
  "access_token": "アクセストークン",
  "expires_in": 3600,
  "scope": "https://www.googleapis.com/auth/devstorage.read_write",
  "token_type": "Bearer"
}
```

ここで得られたアクセストークンを使用してCloud Strageにファイルをアップロードすることができます。
また、先ほど取得した古い方のアクセストークンでも有効期限が切れるまではCloud Strageにファイルをアップロードすることができます。

# 自作アプリに組み込む場合
自作アプリから継続的にAPIを利用するための仕組みを埋め込むためには、「5. curlを用いたアクセストークンとリフレッシュトークンの取得」までを手動で対応したのち、「6. curlを用いたアクセストークンのリフレッシュ」の仕組みを埋め込めば良いと思います。
（アクセストークンの有効期限が切れた場合に、リフレッシュトークンを用いて新しいアクセストークンを取得する）

アクセストークンが有効な時の戻りと、期限切れの時の戻りは以下の通りです。

### アクセストークンが有効な時の戻り

```json
{
 "kind": "xxx",
 "id": "xxx",
 "selfLink": "xxx",
 "name": "xxx",
 "bucket": "xxx",
 "generation": "xxx",
 "metageneration": "xxx",
 "contentType": "xxx",
 "timeCreated": "xxx",
 "updated": "xxx",
 "storageClass": "xxx",
 "timeStorageClassUpdated": "xxx",
 "size": "xxx",
 "md5Hash": "xxx",
 "mediaLink": "xxx",
 "crc32c": "xxx",
 "etag": "xxx"
}
```

### アクセストークンが期限切れの場合の時の戻り

```json
{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "authError",
    "message": "Invalid Credentials",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Invalid Credentials"
 }
}
```

# まとめ

|必要な情報|生成される情報|
|:----------|:-----------|
|[クライアントID] + [スコープ]|Authorization code|
|[クライアントID] + [クライアントシークレット] + [Authorization code]|アクセストークン、リフレッシュトークン|
|[クライアントID] + [クライアントシークレット] + [リフレッシュトークン]|アクセストークン|

Cloud Strageへのアップロードは [アクセストークン] があれば可能

# 参考サイト・関連サイト
OAuth 2.0 Playground
https://developers.google.com/oauthplayground
（curlコマンドはここで得られた結果を利用しています）

OAuth 2.0 Flow: Server-side web apps
https://developers.google.com/youtube/v3/guides/auth/server-side-web-apps

[GCP]API経由でCloud Strageへファイルをアップロードする方法
https://qiita.com/hanzawak/items/355acf2a6b47ea0537c7