Google App Engine Admin API をシェルスクリプトから叩く為にTOKENを取得する

# 目的
GoogleのApp Engine Admin APIをcurlから叩く必要があった。
サーバ側などでシェルスクリプトとして動かすので、refresh_tokenを利用して何度も使える形でトークンを取得したい

# 前提
今回は、2018/12/06に社内で既に利用しているプロジェクトに対し設定したため、説明する手順を実行する際、人によっては課金情報の登録画面や、他の同意画面などが出るかもしれません。
そのあたりについては、適宜読み替えてください。

# 流れ

1. [Developer ConsoleのAPI Manager](https://console.developers.google.com/apis/library)にアクセスして、App Engine Admin APIを選択しAPIを有効にする
2. APIとサービス の 認証情報の画面から、OAuthクライアントIDを作成し、クライアントID,クライアントシークレットIDを取得する
3. コードを取得する
4. refresh_tokenを取得する
5. シェル実行時に、クライアントID,クライアントシークレットID,refresh_tokenをもとにaccess_tokenを取得する
6. access_tokenをheaderに含めてAPIを実行する

# 1. [Developer ConsoleのAPI Manager](https://console.developers.google.com/apis/library)にアクセスして、App Engine Admin APIを選択しAPIを有効にする

[Developer ConsoleのAPI Manager](https://console.developers.google.com/apis/library)にアクセスします。
![step1_API_console.png](https://qiita-image-store.s3.amazonaws.com/0/75491/131d803e-66bd-097b-4395-6d1ebf724891.png "step1_API_console.png")

今回、私の目的はApp Engine Admin APIなので、そちらを選択して有効にします。
![step2_AdminAPI.png](https://qiita-image-store.s3.amazonaws.com/0/75491/560a09ab-53dc-5771-88c6-77f25df429b8.png "step2_AdminAPI.png")

# 2. APIとサービス の 認証情報の画面から、OAuthクライアントIDを作成し、クライアントID,クライアントシークレットIDを取得する
APIを有効にした後、APIとサービスの画面から[認証情報]に移動し、認証情報を作成からOAuthクライアントIDを作成します。
![step3_OAuthClientID.png](https://qiita-image-store.s3.amazonaws.com/0/75491/d30337cf-f9ec-d83c-9e97-0bd4f97815cf.png "step3_OAuthClientID.png")

アプリケーションの種類を「その他」にし、名前を入力します。
![step3_OAuthName.png](https://qiita-image-store.s3.amazonaws.com/0/75491/68c74365-c5ea-7fe8-5fb2-d1f7d7af98de.png "step3_OAuthName.png")
その後、クライアントIDを設定してクライアント ID, クライアント シークレットを記録します。
![step3_clientid.png](https://qiita-image-store.s3.amazonaws.com/0/75491/b1fe4e5b-98df-61a4-1bd2-39c861714fab.png "step3_clientid.png")

# 3. コードを取得する
[OAuth 2.0 Scopes for Google APIs](https://developers.google.com/identity/protocols/googlescopes)を参考に、scopeを設定し、redirect_uri をurn:ietf:wg:oauth:2.0:oobとして、以下にアクセスしましょう

```
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&scope=$SCOPE&access_type=offline
```

私はシェルを作成してURLを作成し、それをブラウザに貼り付けました。

```sh:gae_token.sh
#!/bin/sh

export CLIENT_ID="client_id.apps.googleusercontent.com"
export CLIENT_SECRET="CLIENT_SECRET"

export SCOPE="https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform"
export REDIRECT_URI="urn:ietf:wg:oauth:2.0:oob"

echo "https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&scope=$SCOPE&access_type=offline"
```

確認画面が出た後、コードが表示されるので記録します。

# 4. refresh_tokenを取得する

先程のコードを取得してrefresh_tokenを取得します。

```sh:gae_token.sh
#!/bin/sh

export CLIENT_ID="client_id.apps.googleusercontent.com"
export CLIENT_SECRET="CLIENT_SECRET"
export AUTHORIZATION_CODE="4/AUTHORIZATION_CODE"
export REDIRECT_URI="urn:ietf:wg:oauth:2.0:oob"


curl -X POST --data "code=$AUTHORIZATION_CODE" --data "client_id=$CLIENT_ID" --data "client_secret=$CLIENT_SECRET" --data "redirect_uri=$REDIRECT_URI" --data "grant_type=authorization_code" --data "access_type=offline" https://www.googleapis.com/oauth2/v4/token
```

この時、取得したコードが時間たって無効になっているとBad Requestとでて悩むので注意してください。(それでしばらくハマりました)

```
{ 
  "error": "invalid_grant",
  "error_description": "Bad Request"
}
```

うまくいくとrefresh_tokenが取得できます。
access_tokenは今は無視して、refresh_tokenを記録します。

```
{ 
  "access_token": "access_tokenaccess_tokenaccess_tokenaccess_tokenaccess_tokenaccess_tokenaccess_token",
  "expires_in": 3600,
  "refresh_token": "1/REFRESH_TOKEN",
  "scope": "https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/appengine.admin",
  "token_type": "Bearer"
}%                                                                                                                                                                                                                                                                              
```


# 5. シェル実行時に、クライアントID,クライアントシークレットID,refresh_tokenをもとにaccess_tokenを取得する

refresh_tokenを元に、access_tokenを取得します。

```sh:gae_token.sh
#!/bin/sh

export CLIENT_ID="client_id.apps.googleusercontent.com"
export CLIENT_SECRET="CLIENT_SECRET"
export REFRESH_TOKEN="1/REFRESH_TOKEN"

curl -X POST --data "refresh_token=$REFRESH_TOKEN" --data "client_id=$CLIENT_ID" --data "client_secret=$CLIENT_SECRET" --data "grant_type=refresh_token" https://www.googleapis.com/oauth2/v4/token

```

うまくいけばアクセストークンが取得できます。

```
{
  "access_token": "access_tokenaccess_tokenaccess_tokenaccess_tokenaccess_tokenaccess_token",
  "expires_in": 3600,
  "scope": "https://www.googleapis.com/auth/appengine.admin https://www.googleapis.com/auth/cloud-platform",
  "token_type": "Bearer"
}%
```

# 6. access_tokenをheaderに含めてAPIを実行する

シェルスクリプトで、実行したい処理の前に、APIキーを取得するようにします。
jsonなので処理としてjqコマンドを使いたかったのですが、作業サーバに入っていなかったため、awkを使って処理しました。

```sh:gae_token.sh
#!/bin/sh

export CLIENT_ID="client_id.apps.googleusercontent.com"
export CLIENT_SECRET="CLIENT_SECRET"
export REFRESH_TOKEN="1/REFRESH_TOKEN"

# APIキーの取得処理
export API_KEY=`curl -X POST --data "refresh_token=$REFRESH_TOKEN" --data "client_id=$CLIENT_ID" --data "client_secret=$CLIENT_SECRET" --data "grant_type=refresh_token" https://www.googleapis.com/oauth2/v4/token 2> /dev/null | awk '/access_token/ {match($2, /"(.+)",/, token); print token[1]}'`

# API叩く例
export APPS_ID="test-porject"
export SERVICES_ID="test"
URL="https://appengine.googleapis.com/v1/apps/$APPS_ID/services/$SERVICES_ID/versions/"
curl -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -X GET $URL

```


# 参考

Google APIのAccess Tokenをお手軽に取得する https://qiita.com/shin1ogawa/items/49a076f62e5f17f18fe5