Salesforce 指定ログイン情報: 安全な API 連携のための徹底解説

背景と利用シーン

現代のビジネスアプリケーションは、単独で機能することは稀です。外部のサービスやシステムと連携し、データを交換することで、その価値を最大限に発揮します。Salesforce プラットフォームも例外ではなく、Apex を用いて外部の REST API や SOAP API と通信する機能(コールアウト)は、多くのプロジェクトで不可欠な要素となっています。

しかし、従来の方法では、API のエンドポイント URL や認証情報(API キー、ユーザー名、パスワードなど)を Apex コード内やカスタムメタデータに直接ハードコーディングすることが一般的でした。このアプローチには、いくつかの重大な問題点が存在します。

  • セキュリティリスク: 認証情報がコードやメタデータに平文または難読化された形式で保存されるため、不正なアクセスや情報漏洩のリスクが高まります。コードリポジトリやメタデータのスナップショットから認証情報が流出する可能性があります。
  • メンテナンスの煩雑さ: エンドポイントの URL や認証情報が変更された場合、関連するすべての Apex クラスやメタデータを探し出し、修正し、再デプロイする必要があります。特に、本番環境、Sandbox 環境、開発環境で異なるエンドポイントを利用する場合、管理は非常に複雑になります。
  • 認証処理の複雑化: OAuth 2.0 のような複雑な認証フローを実装する場合、トークンの取得、リフレッシュ、管理といったロジックをすべて Apex で自前で実装する必要があり、開発工数が増大し、バグの温床となり得ます。

これらの課題を解決するために Salesforce が提供する強力な機能が Named Credential (指定ログイン情報) です。Named Credential は、API コールアウトのエンドポイント URL と認証情報を一元的に、かつ安全に管理するための仕組みです。これにより、開発者は認証情報の管理という煩雑な作業から解放され、ビジネスロジックの実装に集中できるようになります。

具体的な利用シーンとしては、以下のようなケースが挙げられます。

  • 外部の気象情報 API を呼び出し、取引先責任者の住所に基づいて最新の天候を表示する。
  • 基幹システム(ERP)の API と連携し、Salesforce 上の商談が成立した際に、ERP に受注情報を作成する。
  • Google Maps API を利用して、カスタムコンポーネント上に取引先の位置情報をマッピングする。
  • 外部の決済ゲートウェイサービスと連携し、Salesforce 内から支払い処理を実行する。

原理説明

Named Credential は、単なる URL と認証情報のコンテナではありません。Salesforce プラットフォームに深く統合された、インテリジェントなコールアウト管理の仕組みです。その中心的な概念は「関心の分離」です。つまり、「どこに接続するか(エンドポイント)」と「どのように認証するか(認証情報)」を分離し、それぞれを宣言的に設定できるようにします。

近年のアップデート(Winter '23 以降)により、この概念はさらに進化し、Named Credential (指定ログイン情報)External Credential (外部ログイン情報) という二つのコンポーネントに分割されました。

1. External Credential (外部ログイン情報)

External Credential は、認証の「方法」と「主体」を定義します。具体的には、認証プロトコル(例: OAuth 2.0, JWT, パスワード認証)と、そのプロトコルで使用する具体的な認証情報(例: ユーザー名、パスワード、コンシューマキー、証明書)を管理します。さらに、その認証情報を誰が利用できるかを制御するための Principal (プリンシパル) を設定します。これにより、「この API キーはシステム全体で共有」「この OAuth トークンは特定のプロファイルのユーザーのみが利用可能」といった柔軟な権限管理が実現できます。

External Credential の利点は、再利用性です。例えば、同じ認証情報(例: 一つの API キー)を複数の異なるエンドポイントで使用する場合、一つの External Credential を作成し、それを複数の Named Credential から参照させることができます。認証情報が変更された場合も、この External Credential を一箇所更新するだけで済みます。

2. Named Credential (指定ログイン情報)

Named Credential は、コールアウトの「宛先」を定義します。具体的には、API のベース URL を指定します。そして、このエンドポイントへの接続時にどの External Credential を使用するかを関連付けます。Apex コードからコールアウトを行う際は、この Named Credential の API 参照名を使用します。

Apex コードが Named Credential を参照してコールアウトを実行すると、Salesforce プラットフォームがバックグラウンドで以下の処理を自動的に行います。

  1. 指定された Named Credential を探し、関連付けられた External Credential を特定します。
  2. External Credential で定義された認証プロトコルに基づき、認証処理を実行します。例えば、OAuth 2.0 であれば、必要に応じてアクセストークンの取得やリフレッシュを自動で行います。
  3. 取得した認証情報(例: `Authorization` ヘッダーにセットされた Bearer トークン)を HTTP リクエストに自動的に付与します。
  4. Named Credential で定義された URL と Apex コードで指定されたパスを結合し、最終的なリクエスト URL を構築して、外部サービスへリクエストを送信します。

この仕組みにより、Apex コードからは認証に関する複雑なロジックが完全に隠蔽されます。開発者は `callout:My_Named_Credential_Name` という形式の特別な URL を指定するだけで、安全で認証済みのコールアウトを簡単に実行できるのです。


サンプルコード

ここでは、`My_Awesome_API` という名前の Named Credential が設定済みであると仮定し、Apex からそれを利用して GET リクエストを送信するシンプルな例を示します。この Named Credential は、`https://api.example.com` という URL を指しており、認証は関連付けられた External Credential によって処理されます。

このコードは、Salesforce の公式ドキュメントで示されている標準的なコールアウトのパターンに基づいています。

// Apexクラスの定義
public class ApiCalloutExample {

    // 非同期でコールアウトを実行するメソッド (@future アノテーションを付与)
    // トリガーなどから直接コールアウトはできないため、非同期処理とするのが一般的
    @future(callout=true)
    public static void performGetCallout() {
        // HttpRequest オブジェクトをインスタンス化
        HttpRequest req = new HttpRequest();

        // setEndpoint メソッドでコールアウト先を指定
        // 'callout:' プレフィックスに続けて Named Credential の API 参照名を指定し、
        // さらにその後に具体的なリソースパスを追記する
        // Salesforce は 'My_Awesome_API' に設定された URL (https://api.example.com) と
        // このパス ('/resource/items') を自動的に結合してくれる
        req.setEndpoint('callout:My_Awesome_API/resource/items');

        // HTTP メソッドを 'GET' に設定
        req.setMethod('GET');

        // Http オブジェクトをインスタンス化してリクエストを送信
        Http http = new Http();
        
        HttpResponse res = null;
        try {
            // send メソッドでリクエストを送信し、レスポンスを受け取る
            // ここで Salesforce が裏側で認証処理をすべて行ってくれる
            res = http.send(req);

            // レスポンスのステータスコードをチェック
            if (res.getStatusCode() == 200) {
                // 成功した場合、レスポンスボディをデバッグログに出力
                System.debug('Success! Response Body: ' + res.getBody());
                // ここで JSON のパースなどの後続処理を行う
            } else {
                // エラーレスポンスの場合
                System.debug('Callout failed. Status: ' + res.getStatus());
                System.debug('Status Code: ' + res.getStatusCode());
                System.debug('Response Body: ' + res.getBody());
            }

        } catch(System.CalloutException e) {
            // コールアウト自体が失敗した場合(例: ネットワークエラー、DNS解決失敗など)
            // CalloutException をキャッチしてエラーハンドリングを行う
            System.debug('Callout error: '+ e.getMessage());
        }
    }
}

このコードのポイント:

  • `req.setEndpoint('callout:My_Awesome_API/resource/items');`: 最も重要な部分です。`callout:` という特別なプロトコルプレフィックスが、Salesforce に対して Named Credential を利用することを示します。URL や認証情報を一切コードに含める必要がありません。
  • 認証ヘッダーが不要: `req.setHeader('Authorization', '...');` のようなコードは一切不要です。Named Credential が自動的に適切な認証ヘッダーを付与してくれます。
  • 非同期実行: DML 操作の後など、同期コンテキストからコールアウトを行う場合は、`@future(callout=true)`、Queueable Apex、Batch Apex などの非同期処理を利用する必要があります。このサンプルでは `@future` を使用しています。

注意事項

Named Credential は非常に便利な機能ですが、利用にあたっていくつかの注意点を理解しておく必要があります。

権限管理

  • 設定の権限: Named Credential や External Credential を作成・編集するには、「アプリケーションのカスタマイズ」権限が必要です。また、認証プロバイダーの設定など、関連する設定には「認証プロバイダーを管理」権限が必要になる場合があります。
  • 実行の権限: Named Credential の認証タイプが `Per User (ユーザごと)` に設定されている場合、どのユーザーがその Named Credential を利用できるかをプロファイルや権限セットで制御する必要があります。管理者は、各ユーザーが外部サービスに対して自身の OAuth トークンで認証を開始できるように設定を有効化する必要があります。意図しないユーザーが API を実行できないように、アクセス権を最小限に留めることが重要です。

API 制限

  • ガバナ制限: Named Credential を使用しても、Salesforce のガバナ制限が緩和されるわけではありません。1 トランザクションあたりのコールアウト回数(同期 Apex では 100 回)、累積タイムアウト時間(120 秒)などの制限は引き続き適用されます。大量のコールアウトを行う場合は、非同期処理の設計を慎重に行う必要があります。
  • 外部サービスのレート制限: 連携先の外部サービス側にも、通常は API のレート制限(例: 1 分あたりのリクエスト数上限)が設けられています。Named Credential を使った実装においても、このレート制限を超えないように、適切な待機処理を入れたり、リクエストをバッチ処理にまとめたりする工夫が必要です。

エラー処理

  • `CalloutException` の捕捉: ネットワークの問題、ホスト名の解決失敗、タイムアウトなど、HTTP レスポンスを受け取る前にコールアウトが失敗した場合、`System.CalloutException` がスローされます。必ず `try-catch` ブロックでこの例外を捕捉し、ユーザーへのフィードバックや再試行ロジックなどを適切に実装してください。
  • HTTP ステータスコードの確認: コールアウトが成功しても、API からはエラー(例: 404 Not Found, 401 Unauthorized, 500 Internal Server Error)が返される可能性があります。`HttpResponse` オブジェクトの `getStatusCode()` メソッドでステータスコードを必ず確認し、2xx 以外のコードに対するハンドリングを実装することが不可欠です。特に、認証情報の期限切れなどで 401 や 403 エラーが返された場合の原因究明に役立ちます。

まとめとベストプラクティス

Named Credential は、Salesforce から外部 API へのコールアウトを実装する上で、現代の標準的な手法と言えます。認証情報のハードコーディングに伴うセキュリティリスクとメンテナンスの煩雑さを排除し、開発者が本来のビジネスロジックに集中できる環境を提供します。

以下に、Named Credential を利用する上でのベストプラクティスをまとめます。

  1. 常に Named Credential を利用する: 新規でコールアウトを実装する場合は、必ず Named Credential を採用してください。既存のハードコーディングされた実装も、リファクタリングの機会があれば Named Credential に移行することを強く推奨します。
  2. External Credential を活用し、責務を分離する: 認証情報(誰が、どのように)は External Credential に、エンドポイント情報(どこへ)は Named Credential に分離して定義します。これにより、コンポーネントの再利用性が高まり、管理が容易になります。
  3. 環境ごとに設定を見直す: Sandbox 環境と本番環境では、コールアウト先のエンドポイント URL が異なることがよくあります。Named Credential の URL は環境ごとに手動で更新するか、CI/CD パイプラインでメタデータをデプロイする際に適切に置換する仕組みを用意してください。
  4. 適切な認証プロトコルを選択する: 連携先の API がサポートする認証方式に応じて、最もセキュアなプロトコル(通常は OAuth 2.0)を選択します。レガシーなシステムとの連携でやむを得ない場合を除き、Password Authentication の利用は慎重に検討してください。
  5. 最小権限の原則を適用する: `Per User` 認証を利用する場合は、プロファイルや権限セットを用いて、その API を利用する必要があるユーザーにのみアクセス権を付与します。システム全体で共有する `Anonymous` 認証の場合も、その Named Credential を呼び出す Apex クラスへのアクセス権を適切に管理します。
  6. 堅牢なエラーハンドリングを実装する: すべてのコールアウト処理は、`CalloutException` の捕捉と、HTTP ステータスコードの検証を含む、包括的なエラーハンドリングロジックを持つべきです。失敗した場合の挙動を明確に定義しておくことが、安定したシステムの構築に繋がります。

Named Credential を正しく理解し、活用することで、あなたの Salesforce 連携ソリューションは、よりセキュアで、より堅牢で、よりメンテナンスしやすいものになるでしょう。

コメント