Stripe Secret Store APIで、APIキーやOAuthのトークンを安全に管理する



この記事は、[Stripe Apps を25日間紹介し続ける Advent Calendar 2022](https://qiita.com/advent-calendar/2022/stripe-apps) 16日目の記事です。

![スクリーンショット 2022-11-24 17.56.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/e0261865-0418-daa2-423a-5f4d70558b1b.png)

Stripe以外のAPIと連携したアプリケーションを開発する場合、API認証のためにAPIキーやOAuthのトークンが必要になります。

この記事では、Stripe AppsアプリでAPIキーやトークン情報を安全に管理するためのAPIについて、紹介します。

## StripeのSecret Store API

Stripeには、アプリごとにAPIキーなどの秘密情報を保存・管理するためのAPIが用意されています。

```typescript
    await stripe.apps.secrets.create({
      scope: {
        type: 'account'
      },
      name: 'example_secret',
      payload: "secret text"
    })
```

`payload`に指定した値を、**Stripeアカウント**または**アカウントに紐づくユーザー単位**で保存できます。

:::note warn
Secret Store APIで、**個人情報**や**クレジットカード情報**などを保存することは**禁止**されています。
:::

## Stripe CLIでSecret Store APIへのアクセス権を設定する

Secret Store APIへのアクセスも、CLIで権限設定が必要です。

```bash
$ stripe apps grant permission "secret_write" "Allows storing secrets between page reloads"
```

## Secret Store APIの「アカウント単位」と「ユーザー単位」

APIキーやOAuthトークンは、サービスによって単位が異なります。

アカウントごとにAPIキーやトークンを発行できるサービスもあれば、ユーザー単位で認証を行う必要があるサービスも存在します。

そのため、StripeのSecret Store APIを利用する場合、**どの粒度でデータを保存するか**を決めることができます。

アカウント単位で利用するデータの場合、`scope.type: 'account'`で保存します。

```typescript
    await stripe.apps.secrets.create({
      scope: {
        type: 'account'
      },
      name: 'example_secret',
      payload: "secret text"
    })
```

もしユーザーごとに利用するトークンやAPIキーが異なるサービスの場合は、`scope.type`を`user`に変更します。

この場合、`src/views`に配置したコンポーネントが取得できる**ユーザーID**を渡す必要があります。

```typescript
const App = ({ userContext }: ExtensionContextValue) => {
  const userId = userContext.id
  const handleSave = useCallback(async () => {
    await stripe.apps.secrets.create({
      scope: {
        type: "user",
        user: userId
      },
      name: 'example_secret',
      payload: "secret text"
    })
  }, [userId])
```

### 保存できるデータ数量の制限

`account`のデータは、１アカウントあたり１０個まで保存できます。

同様に、`user`のデータは、１ユーザーあたり１０個まで保存することができます。

詳細は、以下の記事をご確認ください。

https://stripe.com/docs/stripe-apps/store-secrets#scopes

## 保存したデータを取得・削除する方法

取得したデータの表示や削除には、「保存時に設定したスコープ」と「キーの名前」が最低限必要です。

```typescript
    const { payload } = await stripe.apps.secrets.find({
      scope: { type: 'user', user: userContext.id },
      name: 'secret_name',
      expand: ['payload'],
    })
```

`expand: ['payload']`で明示的にデータを取得しない場合、メタ情報のみ表示される点にご注意ください。

### フロントエンドで保存したデータを、サーバー側で取得する

Secret Store APIを利用するもう１つのメリットは、「Stripeを介して、フロントエンドとサーバーが同じデータにアクセスできる」ことです。

フロントエンドのReactアプリで、APIキーなどの情報を保存します。

```typescript
    await stripe.apps.secrets.create({
      scope: {
        type: "account"
      },
      name: "example_api_key",
      payload: "api_test_xxxx"
    })
```

その後、「同じStripeアカウントを参照する、サーバー側のプログラム」が、このAPIキーをStripe API経由で取得します。

```typescript

    const { payload } = await stripe.apps.secrets.find({
      scope: { type: "account" },
      name: "example_api_key",
      expand: ["payload"],
    })
```

この方法であれば、APIキーの情報を安全に受け渡しすることができます。

バッチ処理やWebhookなどで連携するサービスのアクセス情報を取り扱う際には、このSecret Store APIをご利用ください。

## Documents

https://stripe.com/docs/stripe-apps/store-secrets

https://stripe.com/docs/api/secret_management?lang=node

## Stripe Appsひとりアドベントカレンダー 2022

今年ベータリリースされたばかりのStripe Appsは、まだ日本語の情報が多くありません。

そこでQiita Advent Calendar 2022にて、毎日Stripe Appsについての情報を投稿します。

https://qiita.com/advent-calendar/2022/stripe-apps

ノーコードで利用する方法や、開発するためのTipsなども紹介予定ですので、ぜひ購読をお願いします。