AWS Amplify（Cognito User Pools）で、ユーザーがアカウントを作成したタイミングでStripeにCustomerデータを登録する

この記事は、[AWS AmplifyとAWS×フロントエンド Advent Calendar 2022](https://qiita.com/advent-calendar/2022/amplify) 3日目の記事です。

AWS Amplifyを利用することで、SaaSサービス・アプリケーションのフロントエンドを手早く構築することができます。

その中でも、AmplifyのAuth機能（Cognito User Pools）とStripeの顧客データの連携方法について紹介します。

## StripeのCustomerデータを作成するタイミング(Amplify編)

AWS AmplifyとStripeを連携させる場合、「サブスクリプションなどを紐づける顧客(Customer)データをどのタイミングで作成・紐付けするか」を検討する必要があります。

Customerデータの作成タイミングは、大きく分類するとおよそ以下のパターンが考えられます。

|タイミング|作成方法|
|:-|:-|
|Cognito User Poolsにユーザー情報を作成した時|CognitoのTrigger Lambda|
|サブスクリプションや決済処理に入る前|アプリケーション -> API Gw + Lambda|
|サブスクリプションや決済が完了した後|Stripe Webhook -> API Gw/Lambda|

それぞれメリットデメリットがありますが、今回はCognitoのTriggerを使って作成する方法を紹介します。

## CognitoのUser metadataにCustomerデータを保存する

Cognitoのトリガーでは、次のような構造でデータが送られてきます。

```js
{
  version: '1',
  region: 'us-east-1',
  userPoolId: 'us-east-1_1234',
  userName: 'john',
  callerContext: {
    awsSdkVersion: 'aws-sdk-unknown-unknown',
    clientId: '23445663'
  },
  triggerSource: 'PostAuthentication_Authentication',
  request: {
    userAttributes: {
      sub: 'd8482dbc-1234-abcd-8acc-10f568b6a792',
      'cognito:user_status': 'CONFIRMED',
      email: 'test@example.com'
    },
    newDeviceUsed: true
  },
  response: {}
}
```

この値を利用して、Stripe SDKのカスタマー作成処理を呼び出しましょう。

```javascript
import Stripe from 'stripe';
const stripe = new Stripe('sk_testから始まるAPIキー');

export const handler = async(event) => {
    const customerParams = {
      name: event.userName,
    };
    if (event.request.userAttributes.email) {
        customerParams.email = event.request.userAttributes.email
    }
    await stripe.customers.create(customerParams);
    
    return event;
};
```

この際、CognitoのユーザーにStripeのCustomer IDを設定すると、ログイン中のユーザーの顧客情報が取得しやすくなります。

```diff_javascript
    const customerParams = {
      name: event.userName,
+      metadata: {
+        cognitoUsername: event.userName,
+      },
    };
```

## Cognitoのユーザー情報からStripeのデータを参照できるようにする

CognitoのユーザーIDなどからStripe内の顧客情報を取得するために、作成したCustomer IDをユーザーのmetadataに保存できます。

```diff_javascript
+import { CognitoIdentityProviderClient, AdminUpdateUserAttributesCommand } from "@aws-sdk/client-cognito-identity-provider";
import Stripe from 'stripe';
const stripe = new Stripe('sk_testから始まるAPIキー');

+const client = new CognitoIdentityProviderClient({
+  apiVersion: '2016-04-18',
+  region: 'ap-northeast-1'
+});

export const handler = async(event) => {
    const customerParams = {
      name: event.userName,
    };
    if (event.request.userAttributes.email) {
        customerParams.email = event.request.userAttributes.email
    }
-    await stripe.customers.create(customerParams);
+    const customer = await stripe.customers.create(customerParams);
    
+    const command = new AdminUpdateUserAttributesCommand({
+      UserPoolId: '利用しているUser PoolのID',
+      Username: event.userName,
+      UserAttributes: [{
+        Name: 'customerId',
+        Value: customer.id
+      }],
+    });
+    await client.send(command);
    return event;
};
```

取得したcustomer idを利用して、API側の処理などでStripeとデータを連携させましょう。

## Cognito User Poolsでトリガーを追加する

作成したLambda関数のトリガーへの設定は、Cogniti User Poolsの管理画面からも行えます。

![スクリーンショット 2022-12-03 17.38.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/bd7233f8-e4f8-fcf9-ac7b-8775de54037f.png)


Cognito User PoolsのTriggerでは、「確認後の Lambda トリガー」を利用します。

![スクリーンショット 2022-12-03 17.41.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/850fc7db-801b-44e3-915b-3bffa521faff.png)

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-lambda-post-confirmation.html

「サインアップ前の Lambda トリガー」でも可能ですが、メールなどでの確認ステップが完了していないステータスのため、アクティブではないユーザーのCustomerデータが作成されてしまいます。

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html