サーバー間インテグレーション用の OAuth 2.0 JWT ベアラーフロー
サーバーが情報交換するたびに対話形式のログインをしなくてもデータにアクセスすることを承認したい場合があります。このような場合は、OAuth 2.0 JSON Web トークン (JWT) ベアラーフローを使用できます。このフローは、証明書を使用して JWT 要求に署名し、明示的なユーザー操作を必要としません。ただし、このフローには、クライアントアプリケーションの事前承認が必要です。
必要なエディション
| 使用可能なインターフェース: Salesforce Classic および Lightning Experience の両方 |
| 使用可能なエディション: すべてのエディション |
OAuth 2.0 JWT ベアラートークンフローを使用した場合、クライアントは Salesforce OAuth トークンエンドポイントに JWT を POST します。Salesforce が処理する JWT にはデジタル署名が含まれ、アプリケーションの前の承認に基づいてアクセストークンが発行されます。
次の例は、フローで実行される手順を示しています。
- レポートサービスが、夜間のバッチレポートを開始します。
- 接続アプリケーションは、Salesforce トークンエンドポイントに JWT を送信します。JWT は、ID とセキュリティ情報をセキュリティドメインで共有できるようにします。
- Salesforce が、以前に設定された証明書と追加のパラメーターを使用して、署名を基に JWT を検証します。
- JWT が有効で、接続アプリケーションに事前承認があるものとして、Salesforce がアクセストークンを発行します。事前承認は、次のいずれかの方法で行われます。
- 接続アプリケーションポリシーが [管理者が承認したユーザーは事前承認済み] に設定されている場合、プロファイルと権限セットを使用できます。
- 接続アプリケーションポリシーが [すべてのユーザーは自己承認可能] に設定されている場合、エンドユーザー承認および更新トークンの発行を使用できます。ただし、クライアントは現在の更新トークンまたは保存された更新トークンを必要としません。また、クライアントはクライアントの秘密をトークンエンドポイントに渡す必要もありません。
メモ どちらの場合も、Salesforce は元のアクセストークンに少なくとも 1 つrefresh_token範囲以外の標準の範囲が含まれている場合のみ新しいアクセストークンを発行します。 - 接続アプリケーションがアクセストークンを使用して、Salesforce サーバー上の保護されているデータにアクセスします。
- レポートサービスが、承認されたデータを夜間のレポートに取り込みます。
この認証フローの各ステップを見ていきましょう。
JWT の作成
Salesforce では、署名の秘密としてアップロードされた証明書を使用する RSA SHA256 を使用して JWT が署名されている必要があります。この認証フローを使用する前に、必ず次の手順を実行します。
- X509 証明書を Java キーストア (JKS) にアップロードする。証明書サイズは 4 KB を超えることはできません。超える場合、DER エンコードファイルを使用して、サイズを削減してください。
- 接続アプリケーションの X509 証明書を登録する。この証明書はアプリケーションの非公開鍵に対応しています。接続アプリケーションを保存すると、
client_idとclient_secretが生成され、アプリケーションに割り当てられます。 - JWT を生成するアプリケーションを作成する。JWT は X509 証明書の非公開鍵を使用して署名されます。関連付けられた接続アプリケーションは証明書を使用して署名を検証します。JWT は https://tools.ietf.org/html/rfc7519 で規定されている一般的な形式のルールに準拠する必要がある。
メモ Salesforce は JWT ベアラートークン内の JWT ID (JTI) 要求を必要としません。ただし、JWT ベアラートークン内で JTI 要求を渡した場合、Salesforce は、JTI 要求が以前に送信されていないことを検証します。この検証により、JWT リプレイ攻撃が回避されます。
有効な JWT を作成する手順は、次のとおりです。
- JWT ヘッダーを次の形式で作成します。
{"alg":"RS256"}。 - http://tools.ietf.org/html/rfc4648#page-7 の定義に従って JWT ヘッダーを Base64url エンコードします。結果は
eyJhbGciOiJSUzI1NiJ9と類似しています。 - 次のパラメーターを使用して、JWT の JSON 要求セットを作成します。
JWT の JSON 要求セットの例を次に示します。パラメーター 説明 iss発行者には、証明書を登録した接続アプリケーションの OAuth client_idが含まれている必要があります。aud利用者は認証サーバーを対象利用者として識別します。認証サーバーは、これがトークンの対象利用者であることを確認する必要があります。
利用者の値には認証サーバーの URL https://login.salesforce.com、https://test.salesforce.com、または https://site.force.com/customers (Experience Cloud サイトに実装する場合) を使用します。
subこのフローを Experience Cloud サイトに実装している場合、対象ユーザーにはユーザーのユーザー名が含まれている必要があります。
後方互換性のために、ユーザーは件名 (
prn) の代わりに主要 (sub) を使用することもできます。両方が指定されている場合、prnが使用されます。expトークンが期限切れになる日時 (UTC で測定された 1970-01-01T0:0:0Z からの秒数として表記)。Salesforce ではクロックスキューに 3 分間のバッファが許容されます。たとえば、有効期限が 1,735,743,600 秒または 2025 年 1 月 1 日 15:00:00 UTC に設定されている場合、トークンはこの日付の 15:03:00 UTC まで有効です。 {"iss": "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQ ukXnVjzRgSuQqGn75NL7yfkQcyy7", "sub": "my@email.com", "aud": "https://login.salesforce.com", "exp": "1333685628"} - JWT 要求セットを改行なしで Base64url エンコードします。次に例を示します。
eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa3FlWkt4bm1BaUcxeFY0b0hoOUFLTF9yU0su Qm9TVlBHWkhRdWtYblZqelJnU3VRcUduNzVOTDd5ZmtRY3l5NyIsICJwcm4iOiAibXlAZW1haWwu Y29tIiwgImF1ZCI6ICJodHRwczovL2xvZ2luLnNhbGVzZm9yY2UuY29tIiwgImV4cCI6ICIxMzMz Njg1NjI4In0= - エンコードされた JWT ヘッダーおよびエンコードされた JWT 要求セットの文字列を次の形式で作成します。
次の例では、エンコードされた JWT ヘッダーが強調表示されています。encoded_JWT_Header + "." + encoded_JWT_Claims_SeteyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa3FlWkt4bm1BaUcxeFY0b0hoOUFLTF9yU0su Qm9TVlBHWkhRdWtYblZqelJnU3VRcUduNzVOTDd5ZmtRY3l5NyIsICJwcm4iOiAibXlAZW1haWwu Y29tIiwgImF1ZCI6ICJodHRwczovL2xvZ2luLnNhbGVzZm9yY2UuY29tIiwgImV4cCI6ICIxMzMz Njg1NjI4In0= - JKS から X509 証明書をダウンロードします。
- 結果の文字列に RSA SHA256 を使用して署名します。
- 次の形式で、このステップの文字列を作成します。
次の例では、base64 でエンコードされた署名が強調表示されています。existing_string + "." + base64_encoded_signatureeyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa3FlWkt4bm1BaUcxeFY0b0hoOUFLTF9yU0su Qm9TVlBHWkhRdWtYblZqelJnU3VRcUduNzVOTDd5ZmtRY3l5NyIsICJwcm4iOiAibXlAZW1haWwu Y29tIiwgImF1ZCI6ICJodHRwczovL2xvZ2luLnNhbGVzZm9yY2UuY29tIiwgImV4cCI6ICIxMzMz Njg1NjI4In0=.iYCthqWCQucwi35yFs-nWNgpF5NA_a46fXDTNIY8ACko6BaEtQ9E6h4Hn1l_pcwcK I_GlmfUO2dJDg1A610t09TeoPagJsZDm_H83bsoZUoI8LpAA1s-2aj_Wbysqb1j4uDToz 480WtEbkwIv09sIeS_-QuWak2RXOl1Krnf72mpVGS4WWSULodgNzlKHHyjAMAHiBHIDNt 36y2L2Bh7M8TNWiKa_BNM6s1FNKDAwHEWQrNtAeReXgRy0MZgQY2rZtqT2FcDyjY3JVQb En_CSjH2WV7ZlUwsKHqGfI7hzeEvVdfOjH9NuaJozxvhPF489IgW6cntPuT2V647JWi7ng
次の Java コードは JWT ベアラートークンの簡単な作成例です。
import org.apache.commons.codec.binary.Base64;
import java.io.*;
import java.security.*;
import java.text.MessageFormat;
public class JWTExample {
public static void main(String[] args) {
String header = "{\"alg\":\"RS256\"}";
String claimTemplate = "'{'\"iss\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\", \"jti\": \"{4}\"'}'";
try {
StringBuffer token = new StringBuffer();
//Encode the JWT Header and add it to our string to sign
token.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));
//Separate with a period
token.append(".");
//Create the JWT Claims Object
String[] claimArray = new String[5];
claimArray[0] = "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQukXnVjzRgSuQqGn75NL7yfkQcyy7";
claimArray[1] = "my@email.com";
claimArray[2] = "https://login.salesforce.com";
claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
claimArray[4]=<JTI>
MessageFormat claims;
claims = new MessageFormat(claimTemplate);
String payload = claims.format(claimArray);
//Add the encoded claims object
token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8")));
//Load the private key from a keystore
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("./path/to/keystore.jks"), "keystorepassword".toCharArray());
PrivateKey privateKey = (PrivateKey) keystore.getKey("certalias", "privatekeypassword".toCharArray());
//Sign the JWT Header + "." + JWT Claims Object
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(token.toString().getBytes("UTF-8"));
String signedPayload = Base64.encodeBase64URLSafeString(signature.sign());
//Separate with a period
token.append(".");
//Add the encoded signature
token.append(signedPayload);
System.out.println(token.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}アクセストークンの要求
アクセストークンを要求するために、接続アプリケーションはトークン要求を Salesforce インスタンスのトークンエンドポイントに POST します。POST には JWT が含まれます。
次の例は、トークン要求のサンプルを示しています。
POST /services/oauth2/token HTTP/1.1
Host: login.example.com
Content-Type: application/x-www-form-urlencoded
grant_type= urn:ietf:params:oauth:grant-type:jwt-bearer&
assertion=eyJpc3MiOiAiM01WRz...[omitted for brevity]...ZTPOST に次のパラメーターを含めます。
| パラメーター | 説明 |
|---|---|
grant_type
|
付与種別に次の値を使用します。urn:ietf:params:oauth:grant-type:jwt-bearer |
assertion
|
アサーションは JWT の値全体です。 |
format
|
(省略可能) 予測される戻り形式を指定するために使用します。このパラメーターは、要求のヘッダーを上書きします。次の形式がサポートされます。
|
範囲パラメーター
JWT ベアラートークンフローで範囲を指定することはできません。範囲は、接続アプリケーションの [許可されているユーザー] ポリシーまたは組織の [API アクセスコントロール] 設定に従って発行されます (次の表を参照)。
| 設定 | 結果 |
|---|---|
| [許可されているユーザー] ポリシー: すべてのユーザーは自己承認可能 | 認証が成功すると、アクセストークンと共に返される範囲が前の承認の範囲から取得されます。 |
| [許可されているユーザー] ポリシー: 管理者が承認したユーザーは事前承認済み | 接続アプリケーションに割り当てられた標準範囲とカスタム範囲がアクセストークンと共に返されます。 |
| API アクセスコントロール: 組織の接続アプリケーションを許可リストに登録する | 接続アプリケーションに割り当てられた標準範囲とカスタム範囲がアクセストークンと共に返されます。組織の接続アプリケーションを許可リストに登録していても、予期される範囲を受信しない場合は、次の手順を実行します。
|
Salesforce によるアクセストークンの付与
OAuth 2.0 JWT ベアラーおよび SAML アサーションベアラーフロー要求は、更新トークンを含むユーザーの以前のすべての承認を確認します。一致する承認が見つかった場合、Salesforce は承認された範囲の値を組み合わせます。次に、Salesforce はアクセストークンを発行します。更新トークンまたは承認された使用可能な範囲を含んでいた以前の承認が見つからない場合、要求は未認証として失敗します。
確認が成功すると、Salesforce インスタンスは接続アプリケーションに応答を送信します。OAuth 2.0 JWT ベアラートークンフローのトークン応答は、認証コードフローと同じ形式に従っていますが、更新トークンが発行されることはありません。
次の例は、Salesforce からの応答を示しています。
{"access_token":"00Dxx0000001gPL!AR8AQJXg5oj8jXSgxJfA0lBog.
39AsX.LVpxezPwuX5VAIrrbbHMuol7GQxnMeYMN7cj8EoWr78nt1u44zU31
IbYNNJguseu",
"scope":"web openid api id","instance_url":"
https://yourInstance.salesforce.com","id":"
https://yourInstance.salesforce.com
/id/00Dxx0000001gPLEAY/005xx000001SwiUAAS","token_type":"Bearer"}次のパラメーターはレスポンスボディ内にあります。
| パラメーター | 説明 |
|---|---|
access_token |
接続アプリケーションがクライアントアプリケーションの代わりに保護されたリソースへのアクセスを要求するために使用する OAuth トークン。範囲の形式の追加権限にはアクセストークンが付随することがあります。 |
token_type |
Bearer トークン種別。アクセストークンを含むすべての応答で使用します。 |
scope |
範囲は、接続アプリケーションの [許可されているユーザー] ポリシーまたは組織の [API アクセスコントロール] 設定に従って発行されます。「範囲パラメーター」を参照してください。 |
instance_url |
ユーザーの組織のインスタンスを示す URL。例: https://yourInstance.salesforce.com/。 |
id |
ユーザーを識別し、ユーザーの詳細を照会するために使用できる ID URL。「ID URL」を参照してください。 |
sfdc_site_url |
ユーザーが Experience Cloud サイトのメンバーである場合、サイトの URL が提供されます。 |
sfdc_site_id |
ユーザーが Experience Cloud サイトのメンバーである場合、ユーザーのサイト ID が提供されます。Experience Cloud サイトの場合、このフローにはトークンエンドポイントの "sfdc_site_id" 値が含まれます。このサイト ID は、Connect REST API 要求で必要になる場合があります。 |
保護されたデータへのアクセス
接続アプリケーションは access_token を受信したら、認証ヘッダー要求でベアラートークンとして渡すことができます。次の例は、Experience Cloud サイトへの REST API コールを示しています。
https://site.force.com/customers/services/data/v32.0/ -H
"Authorization: Bearer 00D50000000IehZ\!AQcAQH0dMHZfz972Szmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1E6 LYUfiDUkWe6H34r1AAwOR8B8fLEz6n04NPGRrq0FM"

