SalesforceにおけるOAuth2.0クライアント認証フローの設定とcurlによるREST API呼び出し

# 導入

稼働中のSalesforce REST APIを`curl`コマンドで呼び出せるようにしたく、そのために認証フローを設定したので備忘として残す。可能な認証方法は複数あるが非推奨でなく簡単に設定できそうな[クライアント認証フロー](https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_client_credentials_flow.htm&type=5)での認証をすることにした。

# 設定方法

基本的には公式リファレンスの[こちらの記事](https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_client_credentials_flow.htm&type=5)に則って進めていく。

## 接続アプリケーションの作成・設定

急にアプリケーションと名前に付くものが出てきて面食らうかもしれないが、外部からデータにアクセスする際には接続アプリケーションを作るものらしい。[こちら](https://help.salesforce.com/s/articleView?id=sf.connected_apps_and_external_client_apps_features.htm&type=5)のリファレンスにて以下のように説明されている。

>接続アプリケーションは、Salesforce データを外部アプリケーションに提供するためのフレームワークを提供します。

また、[こちら](https://help.salesforce.com/s/articleView?id=sf.connected_app_about.htm&type=5)に接続アプリケーションのユースケースが記載されている。

#### 接続アプリケーションの作成

最初にアプリケーションマネージャーを開く。
アプリケーションマネージャーは設定>プラットフォームツール>アプリケーション>アプリケーションマネージャーと辿っていけば開ける。

![アプリケーションマネージャー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36377/1b7eccb8-1a45-2f09-47a9-f5b152672a75.png)

「新規接続アプリケーション」ボタンを押下したら各種情報の入力を求められる。基本情報はユーザーごとの適切な値を入力すればよいがAPI(OAuth設定の有効化)は以下のように設定する必要がある。各項目の意味については[こちら](https://help.salesforce.com/s/articleView?id=sf.connected_app_create_api_integration.htm&type=5)を参照。

- OAuth設定の有効化：チェックを入れる
- コールバックURL：使用しないが必須なので適当に入力する(例えば`https://hoge.com`など)
- OAuth範囲：[こちら](https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_tokens_scopes.htm&type=5)を参照しながら適当な範囲を入力する
- サポートされる認証フローにProof Key for Code Exchange(PKCE)拡張を要求にチェックを入れる
- Webサーバーフローの秘密が必要にチェックを入れる
- クライアントログイン情報フローを有効化にチェックを入れる

OAuth範囲について、本記事ではただの接続検証をするだけなのでよく考えずに`Full access(full)`を使うが本来は用件に合わせて適当なものを使用するべきであることを注意しておく。

PKCE拡張は認可コードの傍受を防御するものである。詳しいことはともかく、これを有効にしておくとセキュリティがより強固になる。詳しいことは[こちら](https://help.salesforce.com/s/articleView?id=sf.remoteaccess_pkce.htm&type=5)や[こちら](https://datatracker.ietf.org/doc/html/rfc7636)を参照。

Webサーバーフローの秘密が必要にチェックを入れるとクライアントの秘密鍵を使ってアクセストークンを取得できるようになる。クライアントログイン情報フローとはクライアント認証フローのことであり、チェックを入れることで今回やりたい認証フローが利用可能になる。

入力が完了したら保存ボタンを押下する。

![新規接続アプリケーションの作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36377/971b02f4-b984-8107-1e7f-0f424d9ad90b.png)

#### 接続アプリケーションのポリシーの編集

作成した直後に「接続アプリケーションを管理する」に遷移する。上部に「Manage」ボタンがあるので押下した後、「ポリシーを編集」ボタンを押下する。

下部の方にクライアントログイン情報フロー欄がある。「別のユーザーとして実行」に実行ユーザーを入力する。虫眼鏡ボタンを押下すると設定可能なユーザーの一覧が出てくる。この欄についての説明は[こちら](https://help.salesforce.com/s/articleView?id=sf.connected_app_client_credentials_setup.htm&type=5)に記載があり、以下のように述べられている。

>クライアント資格情報フローではユーザーによる操作はありませんが、Salesforce では実行ユーザーを指定する必要があります。実行ユーザーを選択すると、Salesforce がこのユーザーに代わってアクセス トークンを返すことが許可されます。

![別のユーザーとして実行](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36377/aa2973af-f217-05e0-8793-5f33736846a1.png)


#### コンシューマー鍵とコンシューマーの秘密の取得

アプリケーションマネージャーを再度開く。作成した接続アプリケーションを探し、右端のボタンから参照を選択すると「接続アプリケーションを管理する」に遷移する。

![アプリケーションマネージャー-参照](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36377/b9d3e787-0488-7700-29ac-e52869e3a5cd.png)

API(OAuth設定の有効化)欄に「コンシューマーの詳細を管理」ボタンがあるので押下する。

![コンシューマーの詳細を管理](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36377/3aafb4f6-ae7f-ed0d-f17f-f31b4c469ef1.png)

IDの検証が要求される。「コンシューマーの詳細を管理」ボタン押下後に送られてきたメールに検証用の確認コードが載っているので入力して検証する。

遷移した画面にコンシューマー鍵とコンシューマーの秘密が表示されるため、コピーして控えておく。

# `curl`での呼び出し

最初にアクセストークンを取得する。以下のコマンドを実行する。
コンシューマー鍵とコンシューマーの秘密は前の節で取得したものを利用する。

```shell
$ curl -X POST 'https://{自身のドメイン}.my.salesforce.com/services/oauth2/token?grant_type=client_credentials&client_id={コンシューマー鍵}&client_secret={コンシューマーの秘密}'
```

下記のようなレスポンスが返ってくる。APIの呼び出しには`"access_token"`フィールドの値が必要になる。

```shell
{"access_token":"xxxxxxx.xxxxxxxx","scope":"api","instance_url":"https://{自身のドメイン}.my.salesforce.com","id":"https://test.salesforce.com/id/hoge/fuga","token_type":"Bearer","issued_at":"xxxx"}
```

次に適当なREST APIをコールする。たとえば[使用可能なAPIのバージョンを取得するAPI](https://developer.salesforce.com/docs/atlas.ja-jp.252.0.api_rest.meta/api_rest/resources_versions.htm)にリクエストを送るには下記のコマンドを実行する。

```shell
$ curl -X GET "https://{自身のドメイン}.my.salesforce.com/services/data/" -H 'Authorization: Bearer {access_tokenの値}'
```

ここでヘッダー指定部分をシングルクオーテーション(')で括っているのは`access_token`の値に感嘆符(!)が入っていることによるエラーを防ぐためである（参考：[cURL を使用した REST 要求の送信](https://developer.salesforce.com/docs/atlas.ja-jp.252.0.api_rest.meta/api_rest/intro_curl.htm)）。

他のAPIも基本的には同様に実行できる。ただしAPIごとに仕様が異なるので注意。

# 参考

https://qiita.com/shunkosa/items/ec5fab901401c364ee7a

https://qiita.com/pilot/items/baf71a0ad7ceb3a7965c