くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

StripeのFirebase Extensionsを使ってみた -その1 サンプルを試す編-

Firebase ExtensionsStripeでのサブスク支払い機能が登場!
ずっと便利そうだなぁと思ってたけど、やっとさわれたのでその時の備忘録。

Run Subscription Payments with Stripe拡張機能は、有料プラン(Blaze plan)じゃないと使えないので注意。

公式のデモも公開されている。

まずはサンプルプロジェクトで試してみるところから。 GitHubにサンプルが用意されているので、これを使う。

(サンプル動かす以上のことを書こうと思ったけど、ボリュームが多いので分割...)
(ほぼめぐもっとさんの記事な感じ。記事を読みながら自分用に整理した備忘録版)

1. プロジェクトの準備

1.1. Firebaseプロジェクトの作成

とりあえず、サンプル用のFirebaseプロジェクトを作成し、有料プラン(Blaze)に変更する。

Extensionsを有効にすると、Authentication、Firestore、Functionsを使うため、 それぞれ初期準備を済ませておく
(Firestoreとかを準備をしてなかったので、Extensionsの有効化のときにエラーになった。。)

サンプルだとGoogle認証が使えるので、AuthenticationのGoogle認証を有効にしておく。

2. Extensionsの有効化

2.1. Extensionsのインストール

ここのURLから「コンソールでインストール」を押下し、拡張機能を追加する。

拡張機能を追加するFirebaseプロジェクトの選択画面になるので、作成したプロジェクトを選択する。

すると、初期設定の画面に移動する。
1~3は、拡張機能が作成したりするFunctionsなどの説明。
4が設定項目という感じ。

f:id:wannabe-jellyfish:20210607004051p:plain:w400

それぞれの項目はこんな感じ。

Cloud Functions deployment location
拡張機能が追加してくれるFunctionのリージョン。
Firestoreで選択したものとかがよい。

Products and pricing plans collection
Stripeで追加した商品などの情報がFirestoreに追加されるときのコレクションIDを設定。

Customer details and subscriptions collection
Stripeの顧客や決済情報がFirestoreに追加するときのコレクションIDを設定。

Sync new users to Stripe customers and Cloud Firestore
いつ、StripeとFirestoreに顧客を追加するかの設定。

"Sync"だとAuthenticationに新しいユーザが追加されたときに追加され、 "Do not sync"だと決済したときに追加される。

Automatically delete Stripe customer objects
Stripeの顧客を自動で削除するかどうかの設定。

"Auto delete"だと、AuthenticationかFirestoreで該当のユーザ/ドキュメントが削除された時、Stripe上の顧客を削除し、さらに該当顧客のすぺてのサブスクリプションをキャンセルしてくれる。

Stripe API key with restricted access

StripeのAPIキーを設定。Stripeの「開発者>API キー」で確認・作成できる。
Firebase用に制限付きキーを作成するのが推奨

書き込み権限を3つ(Customers/Checkout Sessions/Customer portal)、
読み込み権限を2つ(Subscriptions/Plans)
で作成する。

Stripe webhook secret
Stripeに登録したWebhookの署名シークレットを設定。

インストール後に設定する項目なので、今はそのままでOK。
(初期設定完了後にStripeに登録するwebhookのURLが表示されるため)

2.2. Extensionsの設定

インストールを開始すると、初期設定するので3~5分くらい待つ感じ。

設定が完了すると、こんな感じの画面に移動できるようになるので、
「この拡張機能の動作」から残りの設定を進めていく。

f:id:wannabe-jellyfish:20210607004516p:plain

2.2.1. Firestoreのルールを設定

「Set your Cloud Firestore security rules」に書いてあるルールをコピペする。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /customers/{uid} {
      allow read: if request.auth.uid == uid;

      match /checkout_sessions/{id} {
        allow read, write: if request.auth.uid == uid;
      }
      match /subscriptions/{id} {
        allow read: if request.auth.uid == uid;
      }
    }

    match /products/{id} {
      allow read: if true;

      match /prices/{id} {
        allow read: if true;
      }

      match /tax_rates/{id} {
        allow read: if true;
      }
    }
  }
}

2.2.2. StripeのWebhookの設定

Stripeで決済が完了したときになど、Firestoreへ同期するときに必要なため、設定をしていく。

「Configure Stripe webhooks」に書いてあるとおりに進めていけばOK。

Stripe上でのWebhookエンドポイントの追加は「開発者>Webhook」から。

エンドポイントURLと必要な送信イベントは、「Configure Stripe webhooks」に書いてあるとおり。

f:id:wannabe-jellyfish:20210607004545p:plain

エンドポイントの追加が完了すると、「署名シークレット」が発行されるので、コピーしておく。

f:id:wannabe-jellyfish:20210607004611p:plain

2.2.3. 署名シークレットの設定

拡張機能をインストールするときに、後回しにした「Stripe webhook secret」を設定する。

「この拡張機能の動作」の下にある「拡張機能の構成」の画面から
拡張機能を再構成」ボタンを押すと編集できる。

「Stripe webhook secret」に先コピーしておいた「署名シークレット」を貼り付けて、保存すればOK。

構成を変更すると、また数分待つ感じ。

2.3. Stripe側の設定

2.3.1. 商品/税率の追加

サンプルを動かす前に、Stripe上に商品や税率を登録しておく必要がある。

「この拡張機能の動作」の「Create product and pricing information」に記載。

商品の登録 ... Stripe上の「商品」から。

f:id:wannabe-jellyfish:20210607004635p:plain

税率の登録 ... Stripe上の「商品>税率」から。

f:id:wannabe-jellyfish:20210607004651p:plain

登録するとFirestoreに同期されてる。
(productions拡張機能で設定したコレクションID)

f:id:wannabe-jellyfish:20210607004902p:plain

Firestoreへの同期は商品の追加時などにWebhookを通じて行われるため、
あらかじめ登録しておいた商品は編集しないと追加されないので注意。

2.3.2. 商品のメタデータを設定

「この拡張機能の動作」の「Assign custom claim roles to products」の内容。

商品のメタデータを設定しておくと、商品を購入したときに、カスタムクレームに設定してくれるよう。

カスタムクレームは、Firebase Authのユーザアカウントに独自の属性を追加/設定できる機能。
Admin SDKからしか設定できないが、拡張機能で追加されるFunctions内でよしなにやってくれる。

これを使うと、

  • Firestoreのセキュリティルールでのチェックに使えたり
  • Client SDK側でどのプランのユーザかを確認できたりする
2.3.2.1. 商品側の設定

こんな感じ。

f:id:wannabe-jellyfish:20210607005022p:plain

設定するメタデータのkeyは「firebaseRole」で固定。

2.3.2.2. カスタムクレームの参照

「この拡張機能の動作」の「Assign custom claim roles to products」の内容のまま。
stripeRole属性に、さっき設定したメタデータがセットされる。

async function getCustomClaimRole() {
  await firebase.auth().currentUser.getIdToken(true);
  const decodedToken = await firebase.auth().currentUser.getIdTokenResult();
  return decodedToken.claims.stripeRole;
}
2.3.3. カスタマーポータルの設定

Stripeでは、顧客が定期支払いのプランや支払い方法を顧客自身が管理できるページを提供してくれている。

デフォルトだとキャンセルもできないようになっているので、設定していく。

「この拡張機能の動作」の「Configure the Stripe customer portal」の内容の通り。

  1. ブランディングの設定 (設定>ブランディング)
    • (テストだけなら、設定なくてもいいかも)
  2. カスタマーポータルの設定 (設定>カスタマーポータル)
  3. 「顧客による支払い方法の変更を許可」をONにする
  4. 「顧客による別の料金プランへの変更を許可」をONにする
  5. 「顧客による定期支払いのキャンセルを許可」をONにする
  6. 顧客が変更できる商品や料金プランを追加する
    • 「顧客による別の料金プランへの変更を許可」をONにした際に必須
  7. 「ビジネス情報」の利用規約とプライバシーポリシーなどを設定

3. サンプルコードを動かしてみる

公式デモのコードがGitHubに上がっているので、動かしてみる。

3.1. サンプルコードのclone

とりあえず、git clone

$ git clone git@github.com:stripe-samples/firebase-subscription-payments.git
$ cd firebase-subscription-payments/

3.2. サンプルコードにAPIキーなどの設定

public/javascript/app.jsに配置されてるファイルにAPIキーなどを設定すればOK。

f:id:wannabe-jellyfish:20210607005207p:plain

  • STRIPE_PUBLISHABLE_KEY
    • Stripeの「開発者>APIキー」にある公開可能キー
    • 標準キーでOK
  • taxRates
    • Stripeの「商品>税率」で追加した税率ID
  • firebaseConfig
    • Firebaseの設定。Firebaseコンソールの設定からWebのマイアプリを追加して表示された内容をコピペ
  • functionLocation
    • 拡張機能で追加した関数のリージョン。今回はasia-northeast1を設定

3.3. Firestoreのインデックスを追加

サンプルコードでは、複合インデックスが必要なクエリがあるため、用意しておく。

f:id:wannabe-jellyfish:20210607005235p:plain

インデックスはFirebase CLIでも設定できる。
firestore.indexes.jsonを作成して、

// firestore.indexes.json
{
  "indexes": [
    {
      "collectionGroup": "prices",
      "queryScope": "COLLECTION",
      "fields": [
        {
          "fieldPath": "active",
          "order": "ASCENDING"
        },
        {
          "fieldPath": "unit_amount",
          "order": "ASCENDING"
        }
      ]
    },
  ],
  "fieldOverrides": []
}

Firebase CLIでデプロイ。

$ firebase deploy --only firestore:indexes

インデックスのビルドが完了したらOK

3.4. サンプルコードの起動

// パッケージのインストール
$ npm install

// Firebaseの設定: 作成したプロジェクトを選択。aliasはdefault
$ firebase use -add

// 起動
$ npm run dev
// => http://localhost:5000

ログインすると、こんな感じで商品の一覧が表示される。
(価格が1円とか2円になってるけど、コードがドルにしか対応してないっぽい)

f:id:wannabe-jellyfish:20210607005253p:plain

テスト用のカードが用意されてるので、それを使って購入してみる。

f:id:wannabe-jellyfish:20210607005341p:plain

決済画面はこんな感じ。

f:id:wannabe-jellyfish:20210607005424p:plain

購入して戻ってみると、プランとカスタムクレームの内容を確認できる。

f:id:wannabe-jellyfish:20210607005508p:plain

カスタマーポータルにアクセスすると、今のプランや支払い方法などが確認できる。

f:id:wannabe-jellyfish:20210607005528p:plain

とりあえず、サンプルは動いた(´ω`)

つづく...

とりあえず、動いたけど、まだまだわからないところがたくさん。
調べて記事にしようと思ったけど、結構なボリュームになったので、分割に...

あとは、

  • Firebase Extensionsの中身
  • サンプルコードの中身
  • StripeのAPI周りの細かいところ

とかを調べる予定!

参考にしたサイト様

Stripe試してみたシリーズ