From 2cc67c417bafb31a91e6fe226995f71e17604936 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 10 Aug 2026 20:20:10 -0700 Subject: [PATCH 1/2] docs(salesforce): correct the setup steps that would strand an admin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified the guide against Salesforce's current UI and docs. Most of it holds; these do not: - The Client Credentials step told admins to check "Enable Client Credentials Flow" under OAuth Policies. On an External Client App that checkbox is under Edit Settings → OAuth Settings; the Policies page holds only the Run As picker, so anyone following it literally hunts for a control that is not on the screen. The FAQ answer inherited the same conflation. - Pre-authorizing the app must go through the profile or a SECOND permission set. A permission set backed by the Salesforce API Integration license cannot hold an Assigned Connected Apps section at all, so the app can never be assigned from the same permission set that grants object access — which produces exactly the "user hasn't approved this consumer" failure that step exists to prevent. This is the likeliest way a JWT setup fails. - Salesforce requires an RSA key of at least 2048 bits; an ECDSA key is silently rejected, and the certificate must stay under 4 KB. - The JWT toggle does not appear until Enable OAuth is on, and the control is "Upload Files". Also scopes the capability promise for the API-only license: SOQL and CRUD on standard objects are supported, reports and dashboards are genuinely unverified in either direction, and Apex Class Access is a permission this license cannot hold, so Tooling API calls touching ApexClass will fail. --- .../salesforce-service-account.mdx | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/docs/content/docs/en/integrations/salesforce-service-account.mdx b/apps/docs/content/docs/en/integrations/salesforce-service-account.mdx index 6ff28bf72b1..fe8f51e41d7 100644 --- a/apps/docs/content/docs/en/integrations/salesforce-service-account.mdx +++ b/apps/docs/content/docs/en/integrations/salesforce-service-account.mdx @@ -56,7 +56,7 @@ External Client Apps are Salesforce's current-generation connected apps and the {/* TODO(screenshot): New External Client App form with the basic details filled in */} - In the OAuth settings section, enable OAuth (exact labels vary by Salesforce release) + Open the app's **Edit Settings** → **API (Enable OAuth Settings)** section and turn on **Enable OAuth** Enter any placeholder **Callback URL** (e.g. `https://login.salesforce.com/services/oauth2/callback`) — it's required by the form but unused by this flow @@ -81,7 +81,7 @@ External Client Apps are Salesforce's current-generation connected apps and the Open your app in **External Client App Manager** and edit its **Policies** - Under **OAuth Policies** → **Client Credentials Flow**, check **Enable Client Credentials Flow** and set **Run As** to the integration user from step 1, then save + Under **OAuth Policies** → **Client Credentials Flow**, set **Run As** to the integration user from step 1, then save. That page holds only the Run As picker — the **Enable Client Credentials Flow** checkbox itself lives in **Edit Settings** → **OAuth Settings**, where you set it in step 2 {/* TODO(screenshot): OAuth Policies with the Run As integration user set under Client Credentials Flow */} @@ -133,9 +133,13 @@ The JWT Bearer Flow authenticates with an uploaded certificate rather than a sha ``` Keep `server.key` somewhere safe — Sim stores it encrypted and never shows it again. + + + Salesforce requires an **RSA** key of at least 2048 bits for this flow; an ECDSA key is rejected. The uploaded certificate must also stay under 4 KB, which a 2048-bit self-signed cert comfortably is. + - In **External Client App Manager** → your app → **Edit Settings** → **OAuth Settings**, enable the **JWT Bearer Flow** toggle and upload `server.crt`. On a legacy Connected App the equivalent is **Use digital signatures** with the same file + In **External Client App Manager** → your app → **Edit Settings** → **OAuth Settings**, turn on **Enable OAuth** (the JWT toggle does not appear until it is on), then **Enable JWT Bearer Flow**, and use **Upload Files** to upload `server.crt`. On a legacy Connected App the equivalent is **Use digital signatures** with the same file Edit the app's **Policies** → **OAuth Policies** and set **Permitted Users** to **Admin approved users are pre-authorized** @@ -145,7 +149,11 @@ The JWT Bearer Flow authenticates with an uploaded certificate rather than a sha - Assign the integration user's **profile** or a **permission set** to the app (External Client App Manager → your app → **Policies** → manage profiles/permission sets), so that user is covered by the pre-authorization + Assign the integration user's **profile** or a **permission set** to the app, so that user is covered by the pre-authorization + + + Assign it through the **profile**, or through a **second permission set that does _not_ carry the Salesforce API Integration permission set license**. A permission set backed by that license cannot hold an **Assigned Connected Apps** / **Assigned External Client Apps** section at all, so the app can never be assigned from the same permission set that grants the user its object access. Getting this wrong produces exactly the `user hasn't approved this consumer` failure this step exists to prevent. + Copy the **Consumer Key** as in step 4. There is no consumer secret to copy — the JWT flow doesn't use one @@ -158,7 +166,7 @@ Go to **Setup** and search for **My Domain**. The host is required — Salesforc - **Production:** `yourorg.my.salesforce.com` - **Sandbox:** `yourorg--sandboxname.sandbox.my.salesforce.com` -- **Developer Edition:** `yourorg-dev-ed.develop.my.salesforce.com` +- **Developer Edition:** `yourorg.develop.my.salesforce.com` (Salesforce appends `-dev-ed` only when it generated the name for you) Sim also accepts other partitioned My Domain hosts (`scratch`, `demo`, `patch`, `trailblaze`, `free`). @@ -176,6 +184,15 @@ There's no scope picking beyond the **api** and **openid** scopes on the app — A permissions gap surfaces at run time as a Salesforce API error; fix it on the integration user's permission sets — no changes are needed in Sim. + +On the **Salesforce Integration** (API-only) license specifically, SOQL and CRUD on standard objects are well supported, but two areas are not safe to assume: + +- **Reports and dashboards** are unverified on this license. Salesforce documents neither a grant nor a prohibition. Test them in a sandbox before depending on them, and remember the user also needs access to the report or dashboard **folder**. +- **Anything Apex-related is blocked** — Apex Class Access is one of the permissions this license cannot hold, so Tooling API calls touching `ApexClass` will fail. Custom field and custom object management is unaffected. + +If a workflow must run reports, a standard-seat integration user is the safe choice. + + ## Adding the Service Account to Sim From fcf8167803c106be34ac68ef68904fa7f5500b83 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 10 Aug 2026 20:24:47 -0700 Subject: [PATCH 2/2] docs(salesforce): align the Developer Edition host in the FAQ with the setup section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setup section was corrected to make the `-dev-ed` suffix conditional, but the FAQ still presented it as mandatory — so an admin whose Developer Edition domain lacks the generated suffix would read two contradictory formats on the same page and validate against a host that does not exist. --- .../content/docs/en/integrations/salesforce-service-account.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/content/docs/en/integrations/salesforce-service-account.mdx b/apps/docs/content/docs/en/integrations/salesforce-service-account.mdx index fe8f51e41d7..e77e619391b 100644 --- a/apps/docs/content/docs/en/integrations/salesforce-service-account.mdx +++ b/apps/docs/content/docs/en/integrations/salesforce-service-account.mdx @@ -247,7 +247,7 @@ Deactivating or freezing the integration user — the Run As user for client cre { question: "Setup → App Manager → New Connected App is greyed out — why?", answer: "Salesforce disabled new Connected App creation by default (new orgs since Summer '25, all orgs since Spring '26); re-enabling it requires a Salesforce Support request. You don't need it — create an External Client App instead (Setup → External Client App Manager), which supports the same Client Credentials Flow and produces the same consumer key and secret." }, { question: "Why do I have to enter a My Domain host instead of login.salesforce.com?", answer: "Salesforce only supports the Client Credentials Flow at your org's My Domain URL — login.salesforce.com and test.salesforce.com are explicitly rejected for this flow. Find yours under Setup → My Domain." }, { question: "The credential validates but a specific tool fails with a permission error — why?", answer: "Every call runs as the Run As user, so the failing tool needs a permission that user doesn't have. Common gaps: Customize Application for custom field/object tools, Run Reports plus folder access for report tools, and object or field permissions for the records involved. Fix it on the integration user's permission sets and re-run." }, - { question: "Does this work with sandboxes and Developer Edition orgs?", answer: "Yes — enter the sandbox host (yourorg--sandboxname.sandbox.my.salesforce.com) or Developer Edition host (yourorg-dev-ed.develop.my.salesforce.com) as the My Domain host. Government/military domains (*.my.salesforce.mil) aren't currently supported." }, + { question: "Does this work with sandboxes and Developer Edition orgs?", answer: "Yes — enter the sandbox host (yourorg--sandboxname.sandbox.my.salesforce.com) or Developer Edition host (yourorg.develop.my.salesforce.com, with a -dev-ed suffix only if Salesforce generated the name for you) as the My Domain host. Government/military domains (*.my.salesforce.mil) aren't currently supported." }, { question: "How do I rotate the credentials?", answer: "For client credentials, rotate the Consumer Secret from the app's OAuth settings (External Client App: Settings → OAuth Settings → Consumer Key and Secret; legacy Connected App: Manage Consumer Details), then update the credential in Sim with the new secret. For JWT bearer, generate a new key pair, upload the new certificate to the app, and paste the new private key into Sim. Either way, reconnecting asks you to restate the authentication method — Sim never returns a stored secret, so it cannot pre-select it for you." }, { question: "What happens if the integration user is deactivated or frozen?", answer: "All token minting fails with invalid_grant and every workflow using the credential stops. Reactivate the user (or point Run As at a new integration user) and runs resume — no changes needed in Sim." }, ]} />