1. やってみたこと
- Salesforceのサーバ間インテグレーション用の OAuth 2.0 クライアントログイン情報フローで認証を行う
- 適当なSalesforce APIにアクセスしてデータ連携を行う
2. バージョンや背景など
- Summer '23 Patch 10.8 (2023/6/30時点)
- sfdx-cli/7.206.6 darwin-x64 node-v18.15.0
% sfdx version
sfdx-cli/7.206.6 darwin-x64 node-v18.15.0
- スクラッチ組織で試してみる
3. 試したこと
サーバ間インテグレーション用の OAuth 2.0 クライアントログイン情報フロー
こちらを参照しながら試していきます
3.1. スクラッチ組織を作成する
以下のようなコマンドでスクラッチ組織を作成します
デフォルトのDevHub組織が既に作成および認証済みとします
sfdx org create scratch --edition developer --alias demo
Your scratch org is ready.
というメッセージが表示され、sfdx org list
で作成したスクラッチ組織を確認できます
以下のコマンドで作成したスクラッチ組織をブラウザで表示します
sfdx org open -o demo
3.2. OAuth 2.0 クライアントのログイン情報フローの接続アプリケーションを設定する
OAuth 2.0 クライアントのログイン情報フローの接続アプリケーションを作成します
OAuth 2.0 クライアントログイン情報フローの接続アプリケーションの設定
こちらを参照しながら作成します
3.2.1. 新規接続アプリケーションの作成
-
設定 > アプリケーション > アプリケーションマネージャ
で新規接続アプリケーション
をクリックします
3.2.2. 基本情報の入力
基本情報を入力します
3.2.3. OAuth設定の入力
OAuth設定を入力します
-
OAuth 設定の有効化
にチェックします -
コールバック URL
を入力します- クライアントログイン情報フローでは使用しない設定のため、任意のもので大丈夫です。ここでは
https://localhost:19999
としました
- クライアントログイン情報フローでは使用しない設定のため、任意のもので大丈夫です。ここでは
-
選択した OAuth 範囲
を選択します- 今回はSalesforce APIを利用するため、
API を使用してユーザデータを管理 (api)
を選択します - クライアントログイン情報フローには、リフレッシュトークンはないため、
いつでも要求を実行 (refresh_token, offline_access)
を選択する必要はありません
- 今回はSalesforce APIを利用するため、
-
Web サーバフローの秘密が必要
をチェックします -
更新トークンフローの秘密が必要
は不要のため、チェック不要です -
クライアントログイン情報フローを有効化
をチェックします
-コンシューマキーとコンシューマの秘密を持つ全員が、選択されたユーザの代理で組織にアクセスできます。
というダイアログが表示されるので、OK
をクリックします -
すべてのトークンを調査
をチェックします
3.2.4. 設定の保存
-
保存
します
3.3. 接続ユーザーの作成
接続ユーザーはAPI限定ユーザーである必要があります
「Salesforce Integration」ライセンスの「Salesforce API Only System Integrations」 というプロファイルでAPI限定ユーザーを作成することができます
このライセンスを利用するとSalesforceライセンスを消費することがありません
-
設定 > ユーザ > ユーザ
で新規ユーザ
をクリックします -
ユーザライセンス
にSalesforce Integration
を設定します -
プロファイル
にSalesforce API Only System Integrations
が自動的に設定されます -
保存
して、ユーザを作成します
3.4. 接続アプリケーションにフローの実行ユーザーを設定
接続アプリケーションで認証した際に実行されるユーザーを設定します
-
設定 > アプリケーション > アプリケーションマネージャ
の該当アプリケーションの右端▼からManage
をクリックします -
ポリシーを編集
をクリックします -
クライアントログイン情報フロー > 別のユーザとして実行
に3.3. 接続ユーザーの作成で作成したユーザを設定します -
保存
します
3.5. アクセストークンを要求する
アクセストークンを要求するためには以下のようなリクエストを送信する必要があります
POST /services/oauth2/token HTTP/1.1
Host: MyDomainName.my.salesforce.com
grant_type=client_credentials&
client_id=*******************&
client_secret=*******************
上記のclient_id
、client_secret
は接続アプリケーションから確認することができます
3.5.1. client_id
、client_secret
の確認
-
設定 > アプリケーション > アプリケーションマネージャ
の該当アプリケーションの右端▼から参照
をクリックします -
API (OAuth 設定の有効化) > コンシューマキーと秘密
のコンシューマの詳細を管理
をクリックします - 確認コードを要求されたら入力して、
検証
をクリックします -
コンシューマ鍵
とコンシューマの秘密
が表示されます -
コンシューマ鍵
がclient_id
、コンシューマの秘密
がclient_secret
に該当します
3.5.2. アクセストークンの取得
以下のようなコマンドで、アクセストークンを取得することができます
curl -X POST 'https://MyDomainName.my.salesforce.com/services/oauth2/token?grant_type=client_credentials&client_id=******&client_secret=******'
そうすると以下のようなレスポンスが返ってきます
access_token
の値を使用してAPIにアクセスを行うことができます
{
"access_token": "******",
"signature": "DnUNtnrNqLdwx4qPha05lg2dFBjRbm2SXydaDqOP/wM=",
"scope": "api",
"instance_url": "https://MyDomainName.my.salesforce.com",
"id": "https://test.salesforce.com/id/******/******",
"token_type": "Bearer",
"issued_at": "1688110510621"
}
また、client_idおよびclient_secretをURLに埋め込まない方式の例は以下になります
HTTPヘッダーAuthorization
にBasic ${client_id:client_secretをbase64エンコードしたもの}
を設定します
echo ${client_id}:${client_secret} | base64
curl -X POST -H 'Authorization: Basic ${base64encoded}' 'https://MyDomainName.my.salesforce.com/services/oauth2/token?grant_type=client_credentials'
こちらも先程のレスポンスと同じものが返ってきます
クライアントログイン情報フローには、リフレッシュトークンはありません
セッションタイムアウト内で取得されるアクセストークンは同じものになります
3.6. GraphQL APIにリクエストしてみる
ここではGraphQL APIにリクエストして、その結果を取得できるかを試してみます
取引先のID
、Name
を取得するクエリーとします
3.6.1. 接続ユーザーに権限を付与
3.6.1.1. 権限セットライセンスの割り当て
接続ユーザーはAPI限定ユーザーであり、権限も限定されています
接続ユーザーに権限セットライセンスSalesforce API Integration
を割り当てることで取引先などへの権限を付与することができるようになります
3.6.1.2. 権限セットの作成
必要な権限は権限セットで付与することになります
-
設定 > ユーザ > 権限セット
で新規
をクリックします -
表示ラベル
、API 参照名
を入力します -
保存
します
-
オブジェクト設定 > 取引先
で編集
をクリックします -
オブジェクト権限 > 参照
の有効
をチェックします -
ID
、Name
(取引先名)はデフォルトで参照可能のため、ここでは設定不要です -
保存
します
3.6.1.3. 権限セットの割り当て
-
設定 > ユーザ > ユーザ
で該当ユーザを選択します -
権限セットの割り当て > 割り当ての編集
をクリックします - 3.6.1.1.で作成した権限セットを選択します
-
保存
します -
権限セットの割り当て
が以下のように表示されます
3.6.2. GraphQL APIにリクエストしてみる
以下のようにGraphQL APIにリクエストを送ります
- ヘッダー
Authorization
にBearer ${access_token}
を設定します - ヘッダー
Content-Type
にapplication/json
を設定します - リクエストボディを以下のようなファイルで用意します
{
"query": "query accounts {
uiapi {
query {
Account {
edges {
node {
Id
Name {
value
}
}
}
}
}
}
}"
}
curl -X POST -H 'Content-Type: application/json' -H 'Authorization: Bearer ******' 'https://MyDomainName.my.salesforce.com/services/data/v58.0/graphql' -d @request_graphql.json
こんな感じの応答が取得できました、
{
"data": {
"uiapi": {
"query": {
"Account": {
"edges": [
{
"node": {
"Id": "001N000002BQxgvIAD",
"Name": {
"value": "Sample Account for Entitlements"
}
}
}
]
}
}
}
},
"errors": []
}
以上で、クライアントログイン情報フローでの、Salesforce APIの利用を試すことができました
4. Appendix
4.1. Salesforceでのリリース時期
-
OAuth 2.0 クライアントのログイン情報フローを使用したサーバ間インテグレーションの設定
- Winter'23
- 2022年10月16日(日本時間)
-
新しい Salesforce インテグレーションユーザライセンスを割り当てて API 限定アクセス権を付与
- Spring'23
このライセンスは 2023 年 3 月 7 日 ~ 8 日の Salesforce 開発者会議 (TrailblazerDX) 中に発表され、2023 年 3 月 14 日からに使用可能になりました。
4.2. 「Salesforce Integration」ライセンスの「Salesforce API Only System Integrations」 プロファイルで作成したユーザーへの権限付与
プロファイルには項目レベルセキュリティ(FLS)を設定することはできそうですが、オブジェクト権限は設定できなそうでした
そのため、細かな権限付与を行うためには「3.6.1. 接続ユーザーに権限を付与」で行ったように、専用の権限セットを作成して割り当てるのが良さそうです
4.3. アクセストークンのタイムアウト
取得したアクセストークンにタイムアウトを設定することができます
- 接続アプリケーションのセッションタイムアウト値で指定することができます
-
接続アプリケーション > Manage > ポリシーを編集 > セッションポリシー > タイムアウト値
で設定します -
--なし--
の場合はタイムアウトしません
-
- 接続アプリケーションのセッションタイムアウト値が
--なし--
の場合は、接続ユーザーのプロファイルのセッションの設定 > セッションタイムアウトの開始条件
が有効になるようです
ただし、セッションタイムアウトになる前にアクセストークンを取得すると、セッションタイムアウトも伸びて、取得してからまたセッションタイムアウト値まで有効のようです
APIをリクエストするトランザクションの最初でアクセストークンを取得するようにすれば十分なのかなと思いました
トランザクション
- アクセストークン取得
- APIへのリクエスト1
- APIへのリクエスト2
Salesforce の OAuth2 トークン 有効期限の仕様が独特だった件について
こちらの記事を参考にしました
4.4. クライアントシークレットの更新
接続アプリケーションに設定されているclient_idおよびclient_secretを更新することができます
ただし、更新している間は認証の挙動が不安定になるようですので運用には注意が必要と思われます
接続アプリケーションのコンシューマ鍵とコンシューマの秘密の循環
詳細はこちらを参照ください
4.5. ログインIPアドレスの制限
接続ユーザーのプロファイルのログイン IP アドレスの制限
で接続元IPアドレスの範囲を設定することができます
これが設定されている場合に、範囲外からのアクセスを防ぐことができます
要件が異なる接続元が複数ある場合は、Salesforce API Only System Integrations
を元にしたカスタムプロファイルをそれぞれ用意して設定するのが良さそうです
5. And more...
OAuth 2.0 クライアントログイン情報フローの接続アプリケーションの設定
こちらに以下のような注意事項が記載されていました
警告 クライアントログイン情報フローを設定する前に、そのセキュリティリスクを理解することが重要です。このフローを有効にすると、接続アプリケーションのコンシューマ鍵とコンシューマの秘密へのアクセス権を持つすべてのユーザまたはアプリケーションがアクセストークンを取得できます。コンシューマの秘密を定期的に変更し、侵害された場合にすぐに変更することで、セキュリティを維持します。「接続アプリケーションのコンシューマ鍵とコンシューマの秘密の循環」を参照してください。
接続アプリケーションのコンシューマ鍵とコンシューマの秘密を変更した場合に、認証できない期間がどうしてもできてしまうのが気になります
client_id
、client_secret
ではなく、JWTを使用したフローも試してみたいと思います
サーバ間インテグレーション用の OAuth 2.0 JWT ベアラーフロー
参考にした記事
サーバ間インテグレーション用の OAuth 2.0 クライアントログイン情報フロー
新しい Salesforce インテグレーションユーザライセンスを割り当てて API 限定アクセス権を付与
OAuth2 Client Credentialsフローを使ったシンプルなSalesforceとのAPI連携
Salesforce の OAuth2 トークン 有効期限の仕様が独特だった件について
OAuth 2.0 全フローの図解と動画
OAuth 2.0 クライアント認証
おわり。
修正メモ
2023/07/06) 3.6.1. 接続ユーザーに権限を付与
の権限付与の方法を修正
接続ユーザーに、権限セットライセンスと権限セットを個別に割り当てする方法に修正しました