開発担当の梅です。今回の記事では、PHPでのSaleForceのOAuth 2.0 JWT認証方法(SandBox環境で検証済み)をご紹介いたします。
Salesforceは世界シェアNo.1の営業支援・CRMツールとして、顧客管理、案件管理、見込み客管理、売上予測、レポートとダッシュボードなど様々な機能が利用でいます。Salesforceの情報を自社システムに同期したいという場合、どうしたらいいでしょうか?

Salesforceはサーバ間のデータ交換でREST APIとSOAP APIを用意してありまして、今回の記事はそれらのWeb サービス APIを利用するためのOAuth 2.0 JWT認証方法を説明します。
目次はこちら
- 1. OpenSSLで非公開鍵と自己署名デジタル証明書を作成する
- 2. Salesforce接続アプリケーションを作成する
- 3. PHPでJWTを作成する
- 4. PHPでアクセストークンを取得する
- 5. PHPでSaleForceから情報を取得する
OpenSSLで非公開鍵と自己署名デジタル証明書を作成する
この証明書は、OAuth 2.0認証で、Salesforceに渡したJWTが有効かどうかを検証するためのものです。基本的にはSalesforceの開発者ガイド「非公開鍵と自己署名デジタル証明書の作成」を参照すれば問題なく作成できます。
作業手順1.非公開鍵を生成し、server.key というファイルに保存します。
openssl genrsa -des3 -passout pass:任意のパスワード -out server.pass.key 2048 openssl rsa -passin pass:任意のパスワード -in server.pass.key -out server.key
作業手順2.server.key ファイルを使用して、証明書署名要求を生成します。server.csr というファイルに証明書署名要求を保存します。
openssl req -new -key server.key -out server.csr Country Name (2 letter code) [XX]:JP <- 会社が所在する国を示す2文字のコード。日本の場合、値はJPです。 State or Province Name (full name) []:Tokyo <- 都道府県 Locality Name (eg, city) [Default City]:Taito <- 市区町村 Organization Name (eg, company) [Default Company Ltd]:tatsuno joho system <- 会社名(任意) Organizational Unit Name (eg, section) []: <- 部署名(任意) Common Name (eg, your name or your server's hostname) []:lms.quizgenerator.net <- 一般名(任意) Email Address []:k.bai@tatsuno-system.co.jp <- メールアドレス(任意) A challenge password []: <- 不要 An optional company name []: <- 不要
作業手順3.server.key および server.csr ファイルから自己署名デジタル証明書を生成します。server.crt というファイルに証明書を保存します。
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
コマンドを実行したパスの直下に、次のように4つのファイルが生成されますが、その中に必要となるのは「server.key」と「server.crt」です。
server.pass.key
server.key
server.csr
server.crt
プライマリキー(署名用)「server.key」の中身はこんな感じです。
-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA09nuSOujeZ0AyR8gZ0jg0MOftWUD64IVJcIrULNCdv5/ZQ8H lvf6lOCs/77FWej07XZaNsBTpllX+yZSs3iFY+VZN/xW+6/e6+vARfPUL6IjnRIp drjXIj811qkvfeWXnZmJQgI7EurhwBgg2Oy2rcZFRL+KJGLhgD9cTkGr06dCIU/B ...省略... QYimkGrlPOzEcFEg/Md3n8UwZ7CSHIG0+xPp/8vnpqNmDPOCw7iEI4iJIyBuTkH4 wzKOvJECgYAJ3ORif2l5LT4KCi5UZL27myUGqyDyt5VPa6H/RB3TChKtpnVcBBDF dCnvFqMv+AC3F2xFpcr3HK2l1H8Ya6yy7QMP9fqgHPWKrkpUSZcT/QvZniCreGsS 7jbhD4R4VOPdu7I6cSWW+lA8mWTwK1Eym0FBl6d8i9q4GrxxcRTv2Q== -----END RSA PRIVATE KEY-----
自己署名デジタル証明書(検証用)「server.crt」の中身はこんな感じです。
-----BEGIN CERTIFICATE----- MIIDpDCCAowCCQDYJxgXlQ+UtjANBgkqhkiG9w0BAQsFADCBkzELMAkGA1UEBhMC SlAxDjAMBgNVBAgMBVRva3lvMQ4wDAYDVQQHDAVUYWl0bzEcMBoGA1UECgwTdGF0 c3VubyBqb2hvIHN5c3RlbTEbMBkGA1UEAwwSYmFpLnF1aXpnZW5kZXYubmV0MSkw ...省略... wpGlYCfAynDVPdE87rI5mitvPFfTAGn+M+kYTaVW4HqVvDMLX+X/3ID0aM5i+k3V 8e2s/GvubOtcYty1nLf4IMtz6ikrfDfiHEmu2nqb+wrsKyvuTwVLakgdKKRYZgQv EIoWUaXAfGDGYyOOsrN6XWwpqp0Yzh51+v1nK+PDBd/fIufge6BDA5EDH3wAJjXu PeTR5HfZoXN5bdBk4KC4ueAGdw8ogbQJ -----END CERTIFICATE-----
Salesforce接続アプリケーションを作成する
作業手順1.Salesforceにログインしたら、右上のメニューから「設定」画面を開きます。

作業手順2.設定画面の左側にあるメニューから「アプリケーションマネージャ」を開き、「新規接続アプリケーション」をクリックします。

作業手順3.接続アプリケーションを設定します。(設定完了後は「保存」を忘れないように)
- 接続アプリケーション名(任意の内容)
- API 参照名(分かりやすい説明を入れましょう)
- 取引先責任者 メール
- OAuth 設定の有効化(必ずチェックを入れてください)
- コールバック URL(利用しませんが、必須入力項目ですから、適当に何かを入力します。)
- デジタル署名を使用(必ずチェックを入れてください)
- 自己署名デジタル証明書(最初の手順で作った「server.crt」を選んでください)
- 選択した OAuth 範囲
※「フルアクセス (full)」だとアクセストークはうまく取れませんでした。- Web 経由のデータへのアクセスを提供 (web)
- データへのアクセスと管理 (api)
- ユーザに代わっていつでも要求を実行 (refresh_token, offline_access)
上記以外の設定内容はデフォルトのままで問題ございません。

作業手順4.「manage」ボタンを押して、管理画面を開きます。(ここはなぜか英語表記になっています。)

作業手順5.「ポリシーを編集」ボタンを押して、ポリシー編集画面を開きます。

作業手順6.「OAuth ポリシー」を次のように設定します。その他の設定はデフォルトのままで問題ございません。設定が終わったら「保存」ボタンを忘れずに押してください。
「OAuth ポリシー」を「管理者が承認したユーザは事前承認済み」に設定したら、アプリケーションの管理画面では「プロファイル」が設定可能になります。

作業手順7.アプリケーションの管理画面にある「プロファイル」設定エリアで「プロフィールを管理する」ボタンを押して、アプリケーションのプロフィールを割当てます。

REST API経由でSaleforceからデータ取得・更新したいので、ここはフル権限を持った「System Admin」を割当てました。
必要に応じて、適切なプロフィールを割当てましょう。

プロフィールの設定内容を保存したら、自動的にアプリケーションの管理画面に戻り、設定結果が確認できます。

PHPでJWTを作成する
SaleForceの開発者ガイドで公開した作成方法はこちらです。
※ドキュメントが古いか、翻訳ミスかはわかりませんが、誤ったところが多くて参考になれませんでした。
JWT(JSON Web Token)構造は大きく分けて、3つの部分になりまして、それぞれ「.」で区切られます。
- ヘッダー(Header)
- ペイロード(Payload)
- 署名(Sinature)
JWT(JSON Web Token)の文字列の全体を見ると、次のようになります。
{ヘッダー>}.{ペイロード}.{署名}
次のように、PHPでSaleForce用のOAuth 2.0 JWTが作成できます。
ここでopenssl_pkey_get_private関数に渡すファイルのパスにハマってしまいました。
ファイルパスは必ず「file://相対パス、または絶対パス」のように書いてください。
function base64UrlEncode($data)
{
return str_replace('=', '', strtr(base64_encode($data), '+/', '-_'));
}
$header = base64UrlEncode(json_encode([
'alg' => 'RS256',
]));
/**
* audについて
* 本番: https://login.salesforce.com
* Sandbox: https://test.login.salesforce.com
* スクラッチ組織: https://test.saleforce.com
*/
$payload = base64UrlEncode(json_encode([
//iss間違ったらエラーメッセージ「接続アプリケーションは存在しない」が返ってきます。
'iss' => '前の手順で作成したSaleForce接続アプリケーションのコンシューマ鍵',
'aud' => 'https://test.salesforce.com',
//sub間違ったらエラーメッセージ「無効なユーザ」が返ってきます。
'sub' => 'SaleForceユーザのログインID',
//ここの期限切れ時間はかなり適当です。exp間違ったらエラーメッセージ「トークが期限切れ」が返ってきます。
'exp' => time() + 3 * 60,
]));
/**
* 署名について
* 前の手順で作成した「server.key」を利用してJWTのヘッダーとペイロードを書名します。
*/
$signature = null;
$privateKey = openssl_pkey_get_private('file://server.key');
openssl_sign($header . '.' . $payload, $signature, $privateKey, OPENSSL_ALGO_SHA256);
openssl_free_key($privateKey);
$signature = base64UrlEncode($signature);
$jwt = $header . '.' . $payload . '.' . $signature;
PHPでアクセストークンを取得する(cUrl利用)
次のように、PHPでSaleForce側にアクセスして、アクセストークを発行して頂きます。
$post = [
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion' => $jwt, //前の手順で作ったJWTの文字列
];
/**
* アクセストークンを取得するAPIについて
* 本番: https://login.salesforce.com/services/oauth2/token
* Sandbox: https://test.login.salesforce.com/services/oauth2/token
* スクラッチ組織: https://test.saleforce.com/services/oauth2/token
*/
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://test.salesforce.com/services/oauth2/token');
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 7);
curl_setopt($ch, CURLOPT_TIMEOUT, 7);
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if($httpcode == 200) {
$json = json_decode($response, true);
if(isset($json['access_token'])) {
$access_token = $json['access_token'];
//do something.
}
} else {
var_dump($httpcode);
var_dump($response);
}
curl_close($ch);
問合せ結果として、次のようなjsonデータが返ってきます。
{
"access_token" => "***********************************",
"scope" => "web id api",
"instance_url" => "https://SaleForce環境名.salesforce.com",
"id" => "https://test.salesforce.com/id/*****/*****",
"token_type" => "Bearer"
}
PHPでSaleForceから情報を取得する
SaleForceの開発者ガイドで公開したデータの問合せ方法の1つ:REST API/Query
PHPでのデータ問合せ方法(cUrl利用):
$query = "SELECT フィールド名 FROM テーブル名";
$query = http_build_query(['q' => $query]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $access_token, //前の手順で取得したアクセストークン(文字列)
]);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_URL, 'https://SaleForce環境名.salesforce.com/services/data/v20.0/query/?' . $query);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 7);
curl_setopt($ch, CURLOPT_TIMEOUT, 7);
//お問い合わせ
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$json = json_decode($response, true);
curl_close($ch);
まとめ
今回の記事では、SaleForceからデータを取得できるまでの手順をご紹介いたしました。
learningBOXもSaleForceと連携可能ですので、ぜひお試しください。