4
2

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.

Salesforceのサーバ間インテグレーション用の OAuth 2.0 クライアントログイン情報フローを試してみる

Last updated at Posted at 2023-06-30

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. 基本情報の入力

基本情報を入力します

  • 接続アプリケーション名, API 参照名, 取引先責任者 メールを設定します
    image.png

3.2.3. OAuth設定の入力

OAuth設定を入力します

  • OAuth 設定の有効化にチェックします
  • コールバック URLを入力します
    • クライアントログイン情報フローでは使用しない設定のため、任意のもので大丈夫です。ここではhttps://localhost:19999としました
  • 選択した OAuth 範囲を選択します
    • 今回はSalesforce APIを利用するため、API を使用してユーザデータを管理 (api)を選択します
    • クライアントログイン情報フローには、リフレッシュトークンはないため、いつでも要求を実行 (refresh_token, offline_access)を選択する必要はありません
  • Web サーバフローの秘密が必要をチェックします
  • 更新トークンフローの秘密が必要は不要のため、チェック不要です
  • クライアントログイン情報フローを有効化をチェックします
      - コンシューマキーとコンシューマの秘密を持つ全員が、選択されたユーザの代理で組織にアクセスできます。というダイアログが表示されるので、OKをクリックします
  • すべてのトークンを調査をチェックします
    image.png

3.2.4. 設定の保存

  • 保存します

3.3. 接続ユーザーの作成

接続ユーザーはAPI限定ユーザーである必要があります
「Salesforce Integration」ライセンスの「Salesforce API Only System Integrations」 というプロファイルでAPI限定ユーザーを作成することができます
このライセンスを利用するとSalesforceライセンスを消費することがありません

  • 設定 > ユーザ > ユーザ新規ユーザをクリックします
  • ユーザライセンスSalesforce Integrationを設定します
  • プロファイルSalesforce API Only System Integrationsが自動的に設定されます
  • 保存して、ユーザを作成します
    image.png

3.4. 接続アプリケーションにフローの実行ユーザーを設定

接続アプリケーションで認証した際に実行されるユーザーを設定します

  • 設定 > アプリケーション > アプリケーションマネージャの該当アプリケーションの右端▼からManageをクリックします
  • ポリシーを編集をクリックします
  • クライアントログイン情報フロー > 別のユーザとして実行に3.3. 接続ユーザーの作成で作成したユーザを設定します
  • 保存します
    image.png

3.5. アクセストークンを要求する

アクセストークンを要求するためには以下のようなリクエストを送信する必要があります

POST /services/oauth2/token HTTP/1.1
Host: MyDomainName.my.salesforce.com
grant_type=client_credentials&
client_id=*******************&
client_secret=*******************

上記のclient_idclient_secretは接続アプリケーションから確認することができます

3.5.1. client_idclient_secretの確認

  • 設定 > アプリケーション > アプリケーションマネージャの該当アプリケーションの右端▼から参照をクリックします
  • API (OAuth 設定の有効化) > コンシューマキーと秘密コンシューマの詳細を管理をクリックします
  • 確認コードを要求されたら入力して、検証をクリックします
  • コンシューマ鍵コンシューマの秘密が表示されます
  • コンシューマ鍵client_idコンシューマの秘密client_secretに該当します

3.5.2. アクセストークンの取得

以下のようなコマンドで、アクセストークンを取得することができます

requst
curl -X POST 'https://MyDomainName.my.salesforce.com/services/oauth2/token?grant_type=client_credentials&client_id=******&client_secret=******'

そうすると以下のようなレスポンスが返ってきます
access_tokenの値を使用してAPIにアクセスを行うことができます

response
{
  "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ヘッダーAuthorizationBasic ${client_id:client_secretをbase64エンコードしたもの}を設定します

client_id:client_secretをbase64エンコード
echo ${client_id}:${client_secret} | base64
request (2)
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にリクエストして、その結果を取得できるかを試してみます

取引先のIDNameを取得するクエリーとします

3.6.1. 接続ユーザーに権限を付与

3.6.1.1. 権限セットライセンスの割り当て

接続ユーザーはAPI限定ユーザーであり、権限も限定されています
接続ユーザーに権限セットライセンスSalesforce API Integrationを割り当てることで取引先などへの権限を付与することができるようになります

image.png

3.6.1.2. 権限セットの作成

必要な権限は権限セットで付与することになります

  • 設定 > ユーザ > 権限セット新規をクリックします
  • 表示ラベルAPI 参照名を入力します
  • 保存します

image.png

  • オブジェクト設定 > 取引先編集をクリックします
  • オブジェクト権限 > 参照有効をチェックします
  • IDName(取引先名)はデフォルトで参照可能のため、ここでは設定不要です
  • 保存します

3.6.1.3. 権限セットの割り当て

  • 設定 > ユーザ > ユーザで該当ユーザを選択します
  • 権限セットの割り当て > 割り当ての編集をクリックします
  • 3.6.1.1.で作成した権限セットを選択します
  • 保存します
  • 権限セットの割り当てが以下のように表示されます

image.png

3.6.2. GraphQL APIにリクエストしてみる

以下のようにGraphQL APIにリクエストを送ります

  • ヘッダーAuthorizationBearer ${access_token}を設定します
  • ヘッダーContent-Typeapplication/jsonを設定します
  • リクエストボディを以下のようなファイルで用意します
request_graphql.json
{
  "query": "query accounts {
    uiapi {
      query {
        Account {
          edges {
            node {
              Id
              Name {
                value
              }
            }
          }
        }
      }
    }
  }"
}
request
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

こんな感じの応答が取得できました、

response
{
  "data": {
    "uiapi": {
      "query": {
        "Account": {
          "edges": [
            {
              "node": {
                "Id": "001N000002BQxgvIAD",
                "Name": {
                  "value": "Sample Account for Entitlements"
                }
              }
            }
          ]
        }
      }
    }
  },
  "errors": []
}

以上で、クライアントログイン情報フローでの、Salesforce APIの利用を試すことができました

4. Appendix

4.1. Salesforceでのリリース時期

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_idclient_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. 接続ユーザーに権限を付与の権限付与の方法を修正

接続ユーザーに、権限セットライセンスと権限セットを個別に割り当てする方法に修正しました

4
2
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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?