オーソリフローを追加する
Stripe アプリに PKCE OAuth ワークフローを実装します。
OAuth バックエンドを構築する代わりに、ダッシュボードの UI 拡張機能を使用して OAuth を実装することで、OAuth プロバイダーからアクセストークンを取得できます。ユーザーが OAuth プロバイダーへのアクセス権を Stripe アプリに付与すると、ダッシュボードの Stripe アプリから直接、その OAuth プロバイダーのサービスを操作できます。
Stripe アプリを使用した OAuth フロー
はじめに
- OAuth プロバイダーが Proof Key for Code Exchange (PKCE) フローに対応していることを確認します。
- まだ作成していない場合は、OAuth プロバイダーを使用してアプリを作成し、Stripe アプリに連結して使用します。
- Stripe アプリを作成して、UI を構築します。UI 拡張機能は、PKCE フローを使用して OAuth プロバイダーからアクセストークンを取得します。
認証リンクを作成する
エンドユーザーは、アプリから認証リンクをクリックして OAuth フローを開始し、OAuth プロバイダーのサービスへのアクセス権をアプリに付与します。
テスト環境と本番環境の OAuth リダイレクト URL を作成します。このリダイレクト URL はアプリに一意のもので、パスにはアプリの
id
が含まれます。たとえば、アプリマニフェストのid
フィールドが"id": "com.
である場合は、以下のようになります。example. oauth-example" - テスト環境の URL は以下のとおりです。
https://dashboard.stripe.com/test/apps-oauth/com.example.oauth-example
- 本番環境の URL は以下のとおりです。
https://dashboard.stripe.com/apps-oauth/com.example.oauth-example
OAuth プロバイダーを使用してテスト環境と本番環境の OAuth リダイレクト URL を登録します。
アプリの UI 拡張機能から、OAuth リダイレクト URL で以下のパラメーターを渡すことにより、OAuth プロバイダーを認証するための、ユーザーを Stripe アプリからルーティングする経路を作成します。
パラメーター 値 reponse_
type これは常に code
です。PKCE フローでは、OAuth プロバイダーから認証コードをリクエストするための値としてcode
が使用されます。client_
id OAuth プロバイダーから割り当てられた OAuth アプリの ID。 redirect_
uri Stripe アプリの OAuth リダイレクト URL。これは、OAuth プロバイダーがユーザーをアプリにリダイレクトするために使用する URL です。 state
createOAuthState 関数からの state
戻り値。code_
challenge createOAuthState 関数からの challenge
戻り値。code_
challenge_ method これは常に S256
です。
次のコード例を使用して、Stripe App からユーザーの経路を選定し、OAuth リダイレクト URL とボタン UI コンポーネントを使用してサードパーティーアプリをオーソリできます。
import { ContextView, Button, } from '@stripe/ui-extension-sdk/ui'; import * as React from 'react'; import {createOAuthState} from '@stripe/ui-extension-sdk/oauth'; import type {ExtensionContextValue} from '@stripe/ui-extension-sdk/context'; const {useState, useEffect} = React; const clientID = 'your_client_id'; const getRedirectURL = (mode: 'live' | 'test') => `https://dashboard.stripe.com/${ mode === 'test' ? 'test/' : '' }apps-oauth/com.example.oauth-example`; const getAuthURL = (state: string, challenge: string, mode: 'live' | 'test') => `https://www.example.com/oauth2/authorize?response_type=code&client_id=${clientID}&redirect_uri=${getRedirectURL(mode)}&state=${state}&code_challenge=${challenge}&code_challenge_method=S256`; const ExampleApp = ({environment}: ExtensionContextValue) => { const {mode} = environment; const [authURL, setAuthURL] = useState(''); useEffect(() => { createOAuthState().then(({state, challenge}) => { setAuthURL(getAuthURL(state, challenge, mode)); }); }, [mode]); return ( <ContextView title="Example"> <Button type="primary" href={authURL} target="_blank">Authorize ExampleApp</Button> </ContextView> ); }; export default ExampleApp;
OAuth プロバイダーからアクセストークンを取得する
アプリは、現在のユーザーの代理としてのみリクエストを行うことができます。ユーザーがアプリを承認した後、ダッシュボードは、oauthContext
コンテキストプロパティの code
および verifier
の値を使用して OAuth データをアプリに渡します。
オーソリの試行が有効な場合のみ、アプリは code
、verifier
、および (該当する場合は) カスタムの state
の値を読み取ることができます。 オーソリの試行が有効になるのは、OAuth プロバイダーが redirect_
にリダイレクトし、オーソリリンクの一致するクエリ文字列パラメーターに state
値が含まれている場合です。state
値は (オーソリリンクを作成したときに) createOAuthState
関数によって返される state
値と同一である必要があります。
アプリの UI 拡張機能で、以下のパラメーターを指定して OAuth プロバイダーからアクセストークンを取得します。
パラメーター | 値 |
---|---|
code | oauthContext. React プロパティの値。 |
grant_ | これは常に authorization_ です。 |
code_ | oauthContext. React プロパティの値。 |
client_ | OAuth プロバイダーからのクライアント ID。 |
redirect_ | Stripe アプリの OAuth リダイレクト URL。 |
以下のコード例を使用して、OAuth プロバイダーからアクセストークンを取得することができます。
import {ContextView} from '@stripe/ui-extension-sdk/ui'; import * as React from 'react'; import type {ExtensionContextValue} from '@stripe/ui-extension-sdk/context'; const {useState, useEffect} = React; // Store the authorization token data. interface TokenData { account_id: string; access_token: string; expires_in: number; } const clientID = 'your_client_id'; const getRedirectURL = (mode: 'live' | 'test') => `https://dashboard.stripe.com/${ mode === 'test' ? 'test/' : '' }apps-oauth/com.example.oauth-example`; // Fetch the authorization token from an example authorization server. const getTokenFromAuthServer = async ({code, verifier, mode}: {code: string, verifier: string, mode: 'live' | 'test'}): Promise<null | TokenData> => { try { const response = await fetch(`https://api.example.com/oauth2/token?code=${code}&grant_type=authorization_code&code_verifier=${verifier}&client_id=${clientID}&redirect_uri=${getRedirectURL(mode)}`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }); if (response.ok) { return await response.json(); } throw new Error(await response.text()); } catch (e) { console.error('Unable to retrieve token from authorization server:', (e as Error).message); return null; } }; const ExampleApp = ({environment, oauthContext}: ExtensionContextValue) => { const [tokenData, setTokenData] = useState<TokenData | null>(null); const code = oauthContext?.code || ''; const verifier = oauthContext?.verifier || ''; const {mode} = environment; useEffect(() => { if (code && verifier && !tokenData) { getTokenFromAuthServer({code, verifier, mode}).then(setTokenData); } }, [code, verifier, mode, tokenData]); return ( <ContextView title="Example" /> ) }; export default ExampleApp;
アクセストークンを設定して見つける
Secret Store API でアクセストークンを設定して見つけると、アプリでそれを保管して後のセッションで使用できるようになります。
アプリに
secret_
権限を追加します。write Command Linestripe apps grant permission "secret_write" "Allows storing secrets between page reloads"
アプリの UI 拡張機能から、Secret Store API でアクセストークンを設定します。
import {ContextView} from '@stripe/ui-extension-sdk/ui'; import * as React from 'react'; import Stripe from 'stripe'; import {createHttpClient, STRIPE_API_KEY} from '@stripe/ui-extension-sdk/http_client'; import type {ExtensionContextValue} from '@stripe/ui-extension-sdk/context'; const {useState, useEffect} = React; interface TokenData { account_id: string; access_token: string; expires_in: number; } const clientID = 'your_client_id'; const getRedirectURL = (mode: 'live' | 'test') => `https://dashboard.stripe.com/${ mode === 'test' ? 'test/' : '' }apps-oauth/com.example.oauth-example`; // Fetch the authorization token from an example authorization server. const getTokenFromAuthServer = async ({code, verifier, mode}: {code: string, verifier: string, mode: 'live' | 'test'}): Promise<null | TokenData> => { try { const response = await fetch(`https://api.example.com/oauth2/token?code=${code}&grant_type=authorization_code&code_verifier=${verifier}&client_id=${clientID}&redirect_uri=${getRedirectURL(mode)}`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }); if (response.ok) { return await response.json(); } throw new Error(await response.text()); } catch (e) { console.error('Unable to retrieve token from authorization server:', (e as Error).message); return null; } }; const stripe = new Stripe(STRIPE_API_KEY, { httpClient: createHttpClient(), apiVersion: '2024-12-18.acacia', }); // Save the token to Secret Store API const saveTokenData = async ({userID, tokenData}: {userID: string, tokenData: TokenData}) => { try { await stripe.apps.secrets.create({ scope: { type: 'user', user: userID }, name: 'oauth_token', payload: JSON.stringify(tokenData), }); } catch (e) { console.error('Unable to save token to Secret Store API:', (e as Error).message); } } const ExampleApp = ({userContext, environment, oauthContext}: ExtensionContextValue) => { const [tokenData, setTokenData] = useState<TokenData | null>(null); const code = oauthContext?.code || ''; const verifier = oauthContext?.verifier || ''; const {mode} = environment; const {id: userID} = userContext; useEffect(() => { if (code && verifier && !tokenData) { getTokenFromAuthServer({code, verifier, mode}).then(tokenData => { if (tokenData) { setTokenData(tokenData); saveTokenData({userID, tokenData}); } }); } }, [code, verifier, mode, userID, tokenData]); return ( <ContextView title="Example" /> ) }; export default ExampleApp;
詳細については、シークレットを設定するをご覧ください。
アプリの UI 拡張機能から、Secret Store API でアクセストークンを見つけます。
import {ContextView} from '@stripe/ui-extension-sdk/ui'; import * as React from 'react'; import Stripe from 'stripe'; import {createHttpClient, STRIPE_API_KEY} from '@stripe/ui-extension-sdk/http_client'; import type {ExtensionContextValue} from '@stripe/ui-extension-sdk/context'; const {useState, useEffect} = React; interface TokenData { account_id: string; access_token: string; expires_in: number; } const stripe = new Stripe(STRIPE_API_KEY, { httpClient: createHttpClient(), apiVersion: '2024-12-18.acacia', }); // Read the token from Secret Store API const getTokenFromSecretStore = async (userID: string): Promise<TokenData | null> => { try { const response = await stripe.apps.secrets.find({ scope: { type: 'user', user: userID }, name: 'oauth_token', expand: ['payload'], }); const secretValue: string = response.payload!; return JSON.parse(secretValue) as TokenData; } catch (e) { console.error('Unable to retrieve token from Secret Store API:', (e as Error).message); return null; } }; const ExampleApp = ({userContext}: ExtensionContextValue) => { const [tokenData, setTokenData] = useState<TokenData | null>(null); const {id: userID} = userContext; useEffect(() => { if (!tokenData) { getTokenFromSecretStore(userID).then(setTokenData); } }, [userID, tokenData]); return ( <ContextView title="Example" /> ) }; export default ExampleApp;
詳細については、シークレットを探すをご覧ください。