2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Stripe Apps を25日間紹介し続けるAdvent Calendar 2022

Day 19

Stripe Appsで、OAuthを利用してGoogleなどの外部サービスとStripeを連携させる方法

Last updated at Posted at 2022-12-19

この記事は、Stripe Apps を25日間紹介し続ける Advent Calendar 2022 19日目の記事です。

スクリーンショット 2022-11-24 17.56.45.png

「Stripeと、外部のSaaSを連携する」

StripeのApp Marketplaceを見ると、MailchimpIntercomDocuSignなど、さまざまなサービスと連携するアプリが公開されています。

スクリーンショット 2022-12-19 11.35.57.png

Stripeが持つ決済やサブスクリプション・顧客の「情報」やプランの変更や請求書の期限超過などの「イベント」を、外部のサービスと連携させることで、よりワークフローを効率的にすることができます。

Stripeとの連携には、OAuthを利用する

Stripe Apps上で外部のサービスにアクセスする場合、OAuthによる認証を推奨しています。

OAuthを利用する場合、Proof Key for Code Exchange(PKCE)フローに対応する必要がありますので、事前にご確認ください。

Google Cloud APIとStripe Appsを連携させる方法

ここからは、連携の例としてGoogle Cloud APIとの連携方法を紹介します。

Google CloudおよびStripeダッシュボードのスクリーンショットは、2022/12時点のものです。
記事作成後、それぞれのサービスがUI・デザインを変更している場合もありますので、ご了承ください。

Step0: Google Cloudで、Gmail APIを有効化する

今回はGmail APIを利用します。

Google CloudのAPIライブラリから、Gmailを検索して有効化しましょう。

[gmail]で検索し、[Gmail API]を見つけたら、[有効にする]ボタンをクリックします。

スクリーンショット 2022-12-19 12.08.21.png

Google Cloud管理画面の[有効なAPIとサービス]に[Gmail API]が表示されていればOKです。

スクリーンショット 2022-12-19 12.10.15.png

Step1: Google Cloudで、OAuth同意画面を作成する

OAuthで認証するための設定をGoogle Cloud側で行います。

Google Cloudの管理画面から、[APIとサービス > OAuth同意画面]へ移動します。

スクリーンショット 2022-12-19 12.03.37.png

[外部]を選び、[作成]をクリックしましょう。

スクリーンショット 2022-12-19 12.03.55.png

公開アプリの場合は、サポートサイトやプライバシーポリシーのURLなどを整備する必要があります。

作成に成功すると、設定画面が開きます。

スクリーンショット 2022-12-19 13.58.12.png

テストユーザーを追加しよう

テストモードで認証をパスさせるために、事前にテストで利用するアカウントを登録します。

[テストユーザー]にて、[+ ADD USERS]をクリックしましょう。

スクリーンショット 2022-12-19 14.04.09.png

メールアドレスを100件まで登録できます。テストに利用したいGoogleアカウントのメールアドレスを追加しましょう。

スクリーンショット 2022-12-19 14.04.17.png

Step2: OAuthの接続情報を発行・取得する

同意画面の用意ができましたので、接続情報を取得します。

Google Cloud管理画面の[接続情報]から[認証情報を作成]を選択し、[OAuthクライアントID]を選びましょう。

スクリーンショット 2022-12-19 13.11.51.png

[アプリケーションの種類]を訊かれますので、[ウェブアプリケーション]を選びましょう。

スクリーンショット 2022-12-19 13.12.19.png

Stripe DashboardのURLを登録する

OAuthでの認証が完了した後に遷移するページなどを登録します。

スクリーンショット 2022-12-19 13.15.06.png

[承認済みのJavaScript]生成元にはhttps://dashboard.stripe.comを登録します。

また、[承認済みのリダイレクトURI]には、https://dashboard.stripe.com/test/apps-oauth/{Stripe AppsのID}を登録しましょう。

[作成]をクリックすると、OAuthクライアントが追加されます。

[JSONをダウンロード]をクリックすると、次のようなJSONがDLできます。

{
    "web": {
      "client_id": "xxxxxx.apps.googleusercontent.com",
      "project_id": "numeric-citron-123456789",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://oauth2.googleapis.com/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_secret": "GOCSPX-xxxxxxxxxxx",
      "redirect_uris": [
        "https://dashboard.stripe.com/test/apps-oauth/com.example.first-stripe-app"
      ],
      "javascript_origins": [
        "https://dashboard.stripe.com"
      ]
    }
  }

Stripe AppsからOAuthの認証画面に遷移する

Google側の設定が終わりましたので、Stripe AppsからGoogleに接続を進めます。

まずはGoogleアカウントでログインするためのUIを用意しましょう。

src/views/App.tsxを次のように変更します。

import { SignInView } from "@stripe/ui-extension-sdk/ui"
import { useEffect, useState } from 'react'
import { ExtensionContextValue } from "@stripe/ui-extension-sdk/context"
import { createOAuthState } from "@stripe/ui-extension-sdk/utils"

// ダウンロードしたクライアントID
const GOOGLE_API_CLIENT_ID = "xxxxxxx.apps.googleusercontent.com"


const App = ({ environment }: ExtensionContextValue) => {  
  const { mode } = environment
  const redirectUrl = [
    "https://dashboard.stripe.com",
    mode === "live" ? null : "test",
    "apps-oauth",
    "{Stripe AppsのID}"
  ].filter(Boolean).join("/")

  const [authURL, setAuthURL] = useState("")
  useEffect(() => {
    createOAuthState()
    .then(({state, challenge}) => {
      const url = new URL("https://accounts.google.com/o/oauth2/auth")
      const params = new URLSearchParams({
        response_type: "code",
        client_id: GOOGLE_API_CLIENT_ID,
        redirect_uri: redirectUrl,
        state,
        code_challenge: challenge,
        scope: "https://www.googleapis.com/auth/gmail.readonly",
        code_challenge_method: "S256"
      })
      setAuthURL(`${url}?${params}`)
    })
  }, [redirectUrl])

  return (
    <SignInView
      description="Googleにログインします。"
      primaryAction={authURL ? {
        label: "ログイン",
        href: authURL
      } : undefined}
    />
  )
}

export default App

変更を保存すると、アプリのUIが次のように変わります。

スクリーンショット 2022-12-19 14.09.34.png

[ログイン]をクリックすると、Googleの認証画面に移動します。

なお、テストモードのため、警告メッセージが表示されることがあります。

スクリーンショット 2022-12-19 14.06.29.png

[続行]をクリックすることで、処理を継続できます。

スクリーンショット 2022-12-19 14.06.37.png

権限の確認画面で、[続行]をクリックすると、Stripeダッシュボードにリダイレクトされます。

認証成功時の処理を追加する

認証画面への移動は実装できましたので、続いてトークンの取得や保存処理を追加しましょう。

Google APIへのアクセス権を設定する

アクセストークンなどを取得するために、Google APIを呼び出す必要があります。

Stripe CLIで、APIを許可リストに追加しましょう。

$ stripe apps grant url "https://oauth2.googleapis.com/token" "Integrate with Google"

関連記事

Google APIを呼び出して、アクセストークンを取得する

続いてGoogle APIからアクセストークンを取得しましょう。

src/views/App.tsxを次のように変更します。

// ダウンロードしたクライアントID
const GOOGLE_API_CLIENT_ID = "xxxxxxx.apps.googleusercontent.com"
// ダウンロードしたクライアントシークレット
const GOOGLE_API_CLIENT_SECRET = "GOCSPXーxxxxx"

-const App = ({ environment }: ExtensionContextValue) => {
+const App = ({ environment, oauthContext }: ExtensionContextValue) => {   
+  const { code, verifier } = oauthContext || {} 
  const { mode } = environment
  const redirectUrl = [
    "https://dashboard.stripe.com",
    mode === "live" ? null : "test",
    "apps-oauth",
    "{Stripe AppsのID}"
  ].filter(Boolean).join("/")

+  useEffect(() => {
+    if (!code || !verifier) return
+    const tokenRequestURL = new URL("https://oauth2.googleapis.com/token")
+    const params = {
+      code,
+      grant_type: "authorization_code",
+      code_verifier: verifier,
+      client_id: GOOGLE_API_CLIENT_ID,
+      client_secret: GOOGLE_API_CLIENT_SECRET,
+      redirect_uri: redirectUrl
+    }
+    fetch(`${tokenRequestURL}?${new URLSearchParams(params)}`, {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/x-www-form-urlencoded"
+      },
+    }).then(response => {
+      if (response.ok) {
+        return response.json()
+      }
+      return response.json().then(error => {
+        throw new Error(`${error.error}: ${error.error_description}`)
+      })
+    }).then(data => {
+      console.log(data)
+    }).catch(console.log) 
+  }, [code, verifier, redirectUrl])

この状態で、再度[ログインボタン]をクリックしてみましょう。

ダッシュボードにリダイレクトされた際、開発コンソールのログにアクセストークンなどが表示されています。

スクリーンショット 2022-12-19 15.27.20.png

*画像のトークンはダミーです。
実際に発行されたトークンをブログやGitHubなどで公開しないようにご注意ください。

取得したアクセストークンを、Stripe Secret Store APIで保存する

取得したアクセストークンを利用できるようにするため、Secret Store APIを使って保存しましょう。

関連記事

まず、Stripe CLIでアクセス権限を設定します。

$ stripe apps grant permission "secret_write" "Store accesst token"

続いてsrc/views/App.tsxを次のように変更します。

import { createOAuthState } from "@stripe/ui-extension-sdk/utils"
+import Stripe from 'stripe'
+import {createHttpClient, STRIPE_API_KEY} from '@stripe/ui-extension-sdk/http_client'

+const stripe = new Stripe(STRIPE_API_KEY, {
+  httpClient: createHttpClient(),
+  apiVersion: '2022-11-15',
+});

-const App = ({ environment, oauthContext }: ExtensionContextValue) => {
+const App = ({ environment, oauthContext, userContext }: ExtensionContextValue) => {
+  const userId = userContext.id

...

    }).then(response => {
      if (response.ok) {
        return response.json()
      }
      response.text().then(text => {
        throw new Error(text)
      })
    }).then(data => {
-      console.log(data)
+      return stripe.apps.secrets.create({
+        scope: {
+          type: 'user',
+          user: userId,
+        },
+        name: "oauth_token",
+        payload: JSON.stringify(data)
+      })
    }).catch(console.log)
-  }, [code, verifier, redirectUrl])
+  }, [code, verifier, redirectUrl, userId])

これでブラウザをリロードしたり、別のデバイスやブラウザからStripeダッシュボードにログインした場合でも、Google APIにアクセスするためのトークンを利用できます。

Gmail APIを呼び出してみよう

最後に取得・保存したアクセストークンを利用して、Gmail APIを呼び出してみましょう。

Stripe CLIで、APIを許可リストに追加しましょう。

$ stripe apps grant url "https://www.googleapis.com/gmail" "Integrate with Google"

続いてGmail APIを呼び出すための処理を、src/views/App.tsxに追加します。


  }, [code, verifier, redirectUrl, userId])

+  useEffect(() => {
+    if (code && verifier) return
+    if (!userId) return 
+    stripe.apps.secrets.find({
+      scope: {
+        type: "user",
+        user: userId,
+      },
+      name: "oauth_token",
+      expand: ["payload"]
+    }).then(({payload}) => {
+      if (!payload) return
+      const secrets = JSON.parse(payload)
+      if (!secrets.access_token) return
+      return fetch(`https://www.googleapis.com/gmail/v1/users/{連携させたGmailアドレス}/messages`, {
+        method: "GET",
+        headers: {
+          "Authorization": `${secrets.token_type} ${secrets.access_token}`
+        }
+      }).then(data => data.json())
+    }).then(console.log)
+    .catch(e => {
+      if (e.code === "resource_missing") {
+        return
+      }
+      console.log(`${e.code}: ${e.message}`)
+    })
+  }, [code, verifier, userId])

  const [authURL, setAuthURL] = useState("")

接続に成功していれば、Gmailのメールスレッド情報が開発コンソールに表示されます。

スクリーンショット 2022-12-19 16.00.27.png

本格的な開発に向けて

この記事では、連携させるところまでを紹介しました。

実際の開発では、次のような要件も発生します。

  • アクセストークンの有効期限が切れた場合のトークンの更新と保存
  • 連携済み or 未連携でアプリのUIを出し分ける
  • 設定画面から、連携の解除や変更ができる機能

決済やサブスクリプションの運用業務を効率化させるための開発や機能提案の1つとして、ぜひ2023年はStripe Appsをご検討ください。

[Tips]一度認証したGoogleアカウントで、再度認証フローに入りたい場合

一度認証に成功し、アクセストークンを取得すると、アクセス権の確認などのページに遷移しなくなります。

認証フローをもう一度試したい場合は、Googleアカウントの[セキュリティ > アカウントにアクセスできるサードパーティアプリ]から登録したアプリを削除しましょう。

スクリーンショット 2022-12-19 15.33.46.png

Documents

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

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

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

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

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?