SaaSプロダクトにおける機能や権限の管理は複雑で手間がかかりがちです。専用のDBテーブルや管理ロジック、そしてサーバー側とフロントエンドの実装が必要になる上、価格改定や新プランの提供開始などで定期的に動きを変更する必要が生まれます。この記事では、2024年にStripeが発表したEntitlements APIを活用して、これらのプラン別アクセス権限管理機能を効率的に実装する方法を紹介します。
SaaSプロダクトにおける機能アクセス権限管理の課題
SaaSプロダクトでは、顧客ごとに異なる料金プランやサブスクリプションに応じて、利用可能な機能を切り替える必要があります。さらに、新サービスの追加や価格の改定などが行われる度に、機能へのアクセス権限の管理ロジックを変更しなければなりません。
これらの管理を自社で行うには、以下のような機能やシステムが必要となります。
- 権限管理システム
- プランや製品と権限のマッピング
- ユーザー情報とプラン・権限のデータ連携
- 価格改定や新プランの追加に伴うシステム改修
これらの開発や運用保守には、少なくないリソースが必要です。そのため、プロダクトのコア機能から注力が逸れがちになり、システムが肥大化し、保守性が低下するなどの問題を生じさせます。
Entitlements APIで実現する機能アクセス権限管理の外部化
StripeのEntitlements APIを利用することで、機能へのアクセス権限管理を製品の外部に委託することができます。
- 料金・商品情報と一緒に「アクセス権限( エンタイトルメント )」情報もStripeで定義・保存します
- 商品とアクセス権限を関連付けることで、プランごとに利用できる権限のマッピングを行います
- 関連付け済みの商品を利用してサブスクリプションを作成するだけで、その顧客がアクセスできる権限を更新できます
- Stripe上の顧客ID(
cus_xxx
)を利用して、その顧客が持つアクセス権限の一覧を取得できます - 利用可能な機能が変更された場合は、webhookでリアルタイムに通知されます
つまり、サービス側では利用可能な機能の一覧を参照するだけで良くなります。
Entitlements APIで、アクセス権限を顧客に付与する方法
それでは実際にアクセス権限の付与を行ってみましょう。ここからはStripe WorkbenchとStripe CLIを利用して設定を行います。
Stripe Workbenchについて
Stripe Workbenchは、2024/05時点でベータ版提供の機能です。そのため、以下のURLからベータ版機能を有効化する必要があります。
Step1: 提供するプランと機能(アクセス権限)を設計する
まずは「どんな製品をいくらで提供するか」や「どのようなアクセス権を付与すべきか」の設計を行いましょう。例えばウェブサイトやアプリケーションのホスティングサービスでは、多くの場合有料プランでのみ独自ドメインの設定ができます。また、LLMをベースとしたAIチャットアプリケーションでは、上位プランでのみ利用できるモデルが用意されています。今回は有料のオンラインメディアサイトを例にして、以下のようなモデルを用意しました。
商品名 | 価格 | 権限 |
---|---|---|
Free | 0円 | 無料記事閲覧 |
Personal | 980円/月 | 無料記事閲覧 / 有料記事閲覧 |
Business | 4,980円/月 | 無料記事閲覧 / 有料記事閲覧 / ビジネスレポート閲覧 |
今回の例は、1ユーザーが1つのプランを契約する体系を想定したモデルです。そのため、上位プランの商品にも下位プランで提供する機能へのアクセス権限を登録するように設計しました。もしホスティングサービスのCDNオプションのような、複数のプランを組み合わせて契約するモデルでは、次のような設計も考えることができます。
商品名 | 価格 | 権限 |
---|---|---|
Hobby | 980円/月 | Webサーバー1台 |
Business | 1980円/月 | Webサーバー1台 / DBサーバー1台 |
CDN Option | 980~円/月 (従量課金) | CDN 1ディストリビューション |
Backup Option | 980円/月 | 10バックアップ |
モデルの設計ができましたので、実装に落とし込みましょう。
Step2: Stripe上に商品・料金とエンタイトルメントを登録する
先ほど作成したモデルに応じて、商品や料金などの情報をStripeに登録します。まずはページ下にある黒いバーをクリックしましょう。クリックすると、Stripeの新しい開発支援ツール「Workbench」が立ち上がります。
Workbenchでは、APIキーやAPIリクエストログ・エラーログそしてWebhookのイベントログなど、Stripeの組み込みや運用保守に必要な情報をまとめて見ることができます。また、StripeのAPIをブラウザ上でテストするStripe Shell機能も用意されており、この記事ではこのStripe Shellを利用して作業を行います。Stripe Shellを起動するため、Workbench上部にあるタブの、Shellをクリックしましょう。
Stripe Shellが起動しました。ここではStripe CLIをブラウザ上で実行できるだけでなく、StripeのAPIやAPIがサポートするパラメータを確認しながら動作テストまで行うことができるAPI Explorer機能も利用できます。ページ右側にあるAPI Explorerの、Resourceをクリックしましょう。
利用できるAPIリソースを表示・検索できるUIが表示されます。ここでproduct
を検索フォームに入力し、Productsを選択してください。Stripe上で商品情報を管理するためのProducts APIが選択された状態となります。
Products APIで利用するメソッドを指定するため、Resource右側にあるMethodを選択しましょう。今回は新しく商品を登録しますので、create
と検索フォームに入力して、Createメソッドを選択します。これでStripeに商品登録を行うAPIをテストする準備ができました。
API ExplorerのParametersにこのAPIで利用できるパラメーターが表示されています。ここに商品や料金の情報を入力することで、商品と料金をまとめて登録することができます。
今回は以下の内容でフォームを入力しましょう。
name | value |
---|---|
name | Free |
default_price_data[currency] | jpy |
default_price_data[unit_amount] | 0 |
default_price_data[recurring][interval] | month |
入力が終わると、次のような表示になります。
また、ページ下部にはAPI Explorerで設定した値がStripe CLIのパラメータとして表示されています。表示されているStripe CLIコマンドをコピーすることで、手元の環境で実行させたり、Wikiや社内チャットにコマンドを共有することもできます。
もしAPI Explorerの操作がうまくいかない場合は、下のコマンドをコピーしてShellに貼り付けてください。
stripe products create --name="Free" \
-d "default_price_data[currency]=jpy" \
-d "default_price_data[unit_amount]=0" \
-d "default_price_data[recurring][interval]=month"
コマンドを入力した状態で**[Enterキー]を押すか、ページ右下のRun**ボタンをクリックすることでコマンドが実行されます。
残りの2商品についても、Stripe Shellで登録しましょう。以下にコマンドを用意しましたので、コピーアンドペーストで実行してください。
stripe products create --name="Business" \
-d "default_price_data[currency]=jpy" \
-d "default_price_data[unit_amount]=4980" \
-d "default_price_data[recurring][interval]=month"
stripe products create --name="Personal" \
-d "default_price_data[currency]=jpy" \
-d "default_price_data[unit_amount]=980" \
-d "default_price_data[recurring][interval]=month"
ダッシュボードの商品カタログページに、3商品が表示されていれば、登録成功です。
Step3: 商品へアクセス権限(エンタイトルメント)を登録する
商品と料金の設定ができましたので、続いて商品ごとの権限設定を行いましょう。Stripeでは、顧客に付与するアクセス権限はプロダクト単位で管理します。それぞれの権限は、Feature
リソースとして登録する必要があり、それをProduct
に紐づける形です。
機能をEntitlements Features
として登録する
まずはFeatureリソースを作成しましょう。API Explorerで以下の値を入力して、3つの権限を登録しましょう。ResourceはEntitlments Features
、 MethodはCreate
を利用します。
無料記事閲覧 | 有料記事閲覧 | ビジネスレポート閲覧 | |
---|---|---|---|
name | 無料記事閲覧 | 有料記事閲覧 | ビジネスレポート閲覧 |
lookup_key | free_posts | paid_posts | biz_reports |
またはStripe Shellに以下の3コマンドをコピーアンドペーストしてもOKです。
stripe entitlements features create --lookup-key="free_posts" --name="無料記事閲覧"
stripe entitlements features create --lookup-key="paid_posts" --name="有料記事閲覧"
stripe entitlements features create --lookup-key="biz_reports" --name="ビジネスレポート閲覧"
エラーメッセージが表示されなければ、登録成功です。
続いて登録した機能を各商品に紐づけましょう。
登録した機能を、商品に紐づける
商品を通してユーザーにアクセス権限を付与するには、商品と機能の関連付けが必要です。これもStripeではAPIを利用して実施します。紐付けには、商品IDが必要です。ダッシュボードの商品カタログページで、付与したい商品の詳細ページに移動しましょう。
Workbenchを開いた状態で、商品の詳細ページに移動すると、画面右下にprod_
から始まる文字列が表示されます。
これをクリックすると、今アクセスしているページのリソース内容をJSONで確認できる「Inspect」タブに移動します。これを利用して、GUIで作成したリソースなどのパラメータを確認することができ、デバッグやAPIリクエストへの落とし込みなどがスムーズに行うことが可能となります。
[Inspect]で表示されている商品IDをコピーして、[Shell]タブに戻りましょう。API Explorerを開いて、ResourceはProduct Features
、 MethodはCreate
を選択しましょう。Path argumentsのid
に、コピーした商品IDを保存します。
続いて紐づける機能IDについては、stripe entitlements features list
コマンドで一覧表示できます。一覧で表示されますので、id
にあるfeat_
から始まるIDをコピーしておきましょう。
コピーしたIDを、API Explorerで表示中のパラメータentitlment_feature
に設定しましょう。これで商品と機能を紐付けするリクエストの準備ができました。
あとは生成されたStripe CLIコマンドを商品へ登録する機能ごとに実行するだけです。
stripe product_features create "Freeの商品ID" --entitlement-feature="無料記事閲覧の機能ID"
stripe product_features create "Personalの商品ID" --entitlement-feature="無料記事閲覧の機能ID"
stripe product_features create "Personalの商品ID" --entitlement-feature="有料記事閲覧の機能ID"
stripe product_features create "Businessの商品ID" --entitlement-feature="無料記事閲覧の機能ID"
stripe product_features create "Businessの商品ID" --entitlement-feature="有料記事閲覧の機能ID"
stripe product_features create "Businessの商品ID" --entitlement-feature="ビジネスレポート閲覧の機能ID"
全てのコマンドを実行すると、紐付け完了です。stripe product_features list prod_から始まる商品ID
を実行することで、商品ごとに設定されている機能を見ることができます。
ここまでで商品ごとのアクセス権限設定と、顧客がサブスクリプションを開始するための前準備が完了しました。
Step4: 顧客を登録し、サブスクリプションを作成する
商品側の設定が完了したので、顧客とサブスクリプションデータを作成してみましょう。ページ上部にあるサブスクリプション作成ボタンをクリックして、作成フォームを表示されましょう。
フォームにテスト用のメールアドレスを入力し、先ほど作成した商品のどれか1つをサブスクリプションの詳細に設定します。その後、支払いに利用するクレジットカードを、4242424242424242
などのテスト用カード番号で登録して、作成を完了させましょう。
サブスクリプションが新しくダッシュボードに表示されていれば、作成成功です。ここの実装方法は、Entitlement APIを利用していない場合と同じです。そのため、Stripe CheckoutやStripe Elementsを利用した場合の実装も、このステップでは追加の作業はありません。
Step5: 顧客にアクセス権限が付与されているかを確認する
サブスクリプションが作成できましたので、顧客にアクセス権限が付与されているかを確認してみましょう。アクセス権限の確認には、顧客のIDが必要です。サブスクリプション一覧ページから、[顧客を表示]ボタンをクリックすることで、顧客情報詳細ページに移動できます。
詳細ページのURLやUIなどで、cus_
から始まる顧客IDをコピーしましょう。あとはStripe Shellでこの値を利用したコマンドを実行するだけです。
stripe active_entitlements list \
--customer="cus_から始まる顧客ID"
このコマンドを実行すると、サブスクリプションへ設定した商品に対応したアクセス権限が取得できます。
このAPIレスポンスで、アクセス権限の名前まで取得したい場合は、expand
パラメータを追加しましょう。
stripe active_entitlements list \
+ -d "expand[0]=data.feature" \
--customer="cus_から始まる顧客ID"
アプリケーションの組み込みでは、lookup_key
に設定したキーを利用して表示や処理の制御を行います。 下のHonoを利用したAPIでは、biz_reports
のキーを持つエンタイトルメントを付与されていない顧客は、プランアップグレードを促すメッセージが表示されます。
app.get('/cus', async c => {
const stripe = new Stripe('sk_test_xxx')
const requiredKey = 'biz_reports'
const entitlements = await stripe.entitlements.activeEntitlements.list({
customer: 'cus_xxxxA'
})
const paidPostFeature = entitlements.data.find(ent => {
return ent.lookup_key === requiredKey
})
if (!paidPostFeature) {
const { data: features } = await stripe.entitlements.features.list({
lookup_key: requiredKey
})
c.status(429)
return c.json({
message: `このページにアクセスするには、「${features[0].name}」権限が必要です。プランをアップグレードしてください。`
})
}
return c.text("Welcome to paid post page!")
})
Step6: サブスクリプションを解約して、アクセス権限を喪失することを確認する
最後に付与したアクセス権限を、解約やダウングレードで喪失できるかを確認しましょう。ダッシュボードでサブスクリプションを解約操作してください。
解約処理が成功したのを確認してから、再びその顧客に付与されたアクセス権限の一覧を取得しましょう。
stripe active_entitlements list \
--customer="cus_から始まる顧客ID"
他にサブスクリプションを契約していない場合、レスポンスが空の配列に変わります。
これによって、プラン変更時に起こるアクセス権限の変化にも、Stripe内のデータを参照するだけで対応できるようになります。
[Advanced Tips] バックエンドで権限変更のワークフローを動かす方法
インフラの構成変更やシステムの設定変更など、サービスによっては権限の喪失や付与に連動したワークフローを実行することがあります。このような権限の変化についても、StripeのWebhookイベントを利用することで、シームレスに連携できます。
プランの変更や解約などに伴う権限の変化に対応するには、新しく追加されたentitlements.active_entitlement_summary.updated
イベントを利用します。このイベントには、「対象の顧客ID」や「変更前と現在の権限設定」などの情報が含まれています。
{
"object": {
"object": "entitlements.active_entitlement_summary",
"customer": "cus_OYXmEvKfYDp7DA",
"entitlements": {
"object": "list",
"data": [],
"has_more": false,
"url": "/v1/customer/cus_OYXmEvKfYDp7DA/entitlements"
},
"livemode": false
},
"previous_attributes": {
"entitlements": {
"data": [
{
"id": "ent_test_61QSA7cL7mjHYxePl41IDF6qBhttt65Y",
"object": "entitlements.active_entitlement",
"feature": "feat_test_61QS9o4tAnK9ATPJX41IDF6qBhttt7Cq",
"livemode": false,
"lookup_key": "paid_posts"
},
{
"id": "ent_test_61QSA7cYW9h6XG8zt41IDF6qBhttt27s",
"object": "entitlements.active_entitlement",
"feature": "feat_test_61QS9nd2kxnCe1ksR41IDF6qBhttt6Ui",
"livemode": false,
"lookup_key": "free_posts"
}
]
}
}
}
このデータを利用することで、「previous_attributes
にしかない権限がある場合、それに関連したリソースやDBを変更するワークフローを実行する」といった設定ができます。
まとめ
新しく発表されたEntitlement APIを利用することで、プランごとにユーザーへ付与するアクセス権限の管理についてもStripeで管理できるようになります。すでに権限管理をIDPサービスや独自のDBで管理している場合でも、Webhookイベントを利用することで権限の付与や喪失をリアルタイムで反映させることが可能です。
新しいサービスのローンチとPMFをより高速に実現させるため、ぜひサブスクリプションにStripeをご利用ください。
Document: