サーバから Soracom API を叩くために API Key と Token をどうやって取得するべきか

Soracom API を叩くには `API Key` と `Token` のペアが必用となる。

例:  

```bash
curl -X GET \
  --header 'Accept: application/json' \
  --header 'X-Soracom-API-Key: api-xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx' \
  --header 'X-Soracom-Token: eyJQiOiJBUraWUVDQ(以下略)' \
  'https://api.soracom.io/v1/subscribers/your_imsi/data?sort=desc'
```

この `API Key` と `Token` をサーバとかLambdaとか、要はUIの無いバックエンドサービスからどう叩くべきか？の話。  
基本、公式ドキュメントをはじからはじまでちゃんと目を通せば書いてあるのだが、以下の要因からすげー迷ったので備忘録兼ねて書いとく。

* 巷にあふれる解説記事が [API Reference](https://dev.soracom.io/jp/docs/api/) で暫定的に取得した値を使用する前提のものが多い。
* 認証に係る要素が、 `Auth Key ID`, `Auth Key Secret`, `API key`, `Token` の 4セットあるのだが、
    * 日本語と英語の表記の空目
    * `API Key` と `Auth Key ID` がまぎらわしい。
    * 公式APIでも `Auth Key Secret` を入れるべきフィールドを `authKey` ってたりするので、仕様書読んでて混乱する。
* 先にAPIリファレンスを斜め読みして、 `API Key` で調べて [SORACOM API 利用ガイド](https://dev.soracom.io/jp/docs/api_guide/) の **「API Key と API Token」 だけ** 読むと混乱する。
    * その数項目先の **「API 呼び出し例」** まで読み進めると、認証に係る4つの要素の使い分けをちゃんと理解できる。
* Ruby 以外に公式のSDKが無い。
* 公式ドキュメントにユースケースとベストプラクティスがあんま載ってない。


## Overview

* まず、プログラムアクセス用の SAMユーザを作れ。
    * AWS の IAM ユーザと同じ理解。
* SAMユーザの **認証キーID** (`Auth Key Id`) と **認証キーシークレット** (`Auth Key Secret`) は固定で持ってOK。
    * AWS Secrets Manager で管理するなり、 CIで環境変数に突っ込むなりお好きにどうぞ。
    * ただし、これは絶対に漏らしたらNG。漏れたら再発行する。
* `API Key` と `Token` は SAMユーザの認証を通すことによって即時で発行して使い捨てるべきもの。

ちゃんと Overview 理解できてればシンプルで使いやすいよ！

## 詳細

### SAM ユーザ作成

* 基本は公式ドキュメントの通りでOK 
    * [SORACOM Access Management を使用して操作権限を管理する](https://dev.soracom.io/jp/start/sam/)
* コンソールログイン用のパスワードは設定するな。何のためにSAMユーザ分けたかわからなくなる。
* SAM ユーザーの権限設定 は多分 `:list*` とか `:get*` とか。かならず絞るように。

### API Key, Token の取得

[SORACOM API 利用ガイド](https://dev.soracom.io/jp/docs/api_guide) の **1. API Key, API Token の取得** の **SAM ユーザーの API Key と API Token を取得する例** を参照のこと。 
具体的には以下。  

```bash
curl  -X POST \
      -H 'Content-Type: application/json' \
      -d '{"authKeyId": "keyId-xxxxxxx", "authKey": "secret-xxxxxxx"}' \
      https://api.soracom.io/v1/auth

# Response:
# 200 OK
#
# {
#   "apiKey": "API Key",
#   "token": "API Token",
#   "operatorId": "当該OperatorのID",
#   "userName": "SAMユーザー名"
# }
```

なお、node で axios 使う場合はこんな感じ。

```javascript
const axios = require('axios');

const getTokenByAuthKey = async (authKeyId, authKeySecret, tokenTimeoutSeconds) => {
    const url = 'https://api.soracom.io/v1/auth';
    const body = {
        authKeyId,
        authKey: authKeySecret,
        tokenTimeoutSeconds
    }; 
    const headers = { 'Content-Type': 'application/json' };
    const res = await axios.post(url, body, { headers, responseType: 'json' });
    console.log(res.data);
    const apiKey = res.data.apiKey;
    const token = res.data.token;
    // const operatorId = res.data.operatorId;
    return { apiKey, token };
};

// SAM user の情報 (認証キー ID と認証キーシークレット)
const authKeyId = 'keyId-xxxxxxxxxxxxxxxxxxxxxxxxxxx';
const authKeySecret = 'secret-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

// SAM user の認証をかけて、 API Key, Token を取得する
const tokenTimeoutSeconds = 3 * 60; // 最短3分
const { apiKey, token } = await getTokenByAuthKey(authKeyId, authKeySecret);
// 以降、 apiKey, token を使用して Soracom の API を呼び出しできる。

```

理解すればこんだけ。

- `tokenTimeoutSeconds` は [SORACOM API 利用ガイド](https://dev.soracom.io/jp/docs/api_guide/) によれば 「デフォルトでは24時間で、最短3分、最長で48時間まで指定でき」る。
    - 通常のサーバちっくなデータ取得であれば 3分あれば十分すぎるので、3分で良い認識。
- `operatorId` は別途設定で持つでいいと思うが、auth のレスポンスで取得できるものを使うでも良さそう。
    - API設計思想的にどっちを想定してるんだろう？

## その他

公式の [API Reference](https://dev.soracom.io/jp/docs/api/) 読んでも `API Key`, `Token` をどうやって取得するか書いてないので、ぐぐるじゃないですか？

![スクリーンショット 2020-11-23 10.26.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52410/48884327-544e-eac2-470b-2a22dab1a99f.png)

「API Key と API Token に移動」 するじゃないですか？

![スクリーンショット 2020-11-23 10.29.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52410/da1e01ae-f213-02a8-fde9-9e34a4ca118c.png)

え、Token更新し続けろって言ってる？ってなるんすわ。  

このページをだーっと下まで読んでいって「1. API Key, API Token の取得」まで行くと、別途SAMユーザと認証キーID/認証キーシークレットがちゃんとあるのね！って理解できる。。。  


あと、流石にそろそろ公式で node 版の SDKが欲しいです．．． async/await 対応したやつ．．．．．． 
(Soracom Beam 使えってことですよねわかります)