Salesforce
www.salesforce.com · CRM · for: AI agent reads and updates CRM records (accounts, opportunities) in each customer's Salesforce org.
Sign up for a free Developer Edition org and decide now whether you'll join the Salesforce Partner Program (Partner Business Org as Dev Hub). That decision determines where your packaged External Client App, and therefore your client ID, will live.
Your path at a glance
Watch out for
- BlockerOld tutorials say 'create a connected app' — you can't anymorewhy & fix →
- BlockerA local ECA only serves its own orgwhy & fix →
- WarningUninstalled apps are blocked for new users (since Sept 2025)why & fix →
- WarningRefresh tokens die after 30 idle days (Nov 4, 2026 in production)why & fix →
- WarningRotation races and silent revocationswhy & fix →
- WarningProfessional/Group Edition customers can't use the APIwhy & fix →
- WarningA Developer Edition Dev Hub can strand your packagewhy & fix →
- InfoAPI calls to login.salesforce.com failwhy & fix →
Before you start
Steps
Prepare
Configure OAuth
Test with your account
Review & verification
Launch to customers
- 9Publish an admin install guideAgent can dodetails →
Copy & paste
apirefresh_tokenid- Developer console
- https://login.salesforce.com/
- OAuth docs
- https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm&type=5
- Authorize URL
- https://login.salesforce.com/services/oauth2/authorize
- Token URL
- https://login.salesforce.com/services/oauth2/token
- Discovery
- https://login.salesforce.com/.well-known/openid-configuration
Show prompt
You are adding a multi-tenant Salesforce integration to this codebase so an AI agent can read and update Accounts and Opportunities in each customer's Salesforce org.
Constraints (as of Oct 2026):
- Use an External Client App (ECA), not a connected app. New connected apps can't be created.
- OAuth 2.0 web-server flow with PKCE (S256), sending both client_secret and code_verifier. Scopes: 'api refresh_token id'.
- Login host depends on the connection: https://login.salesforce.com (production and Developer Edition), https://test.salesforce.com (sandbox), or a customer-supplied https://<mydomain>.my.salesforce.com. Validate that My Domain input ends in .my.salesforce.com.
- Persist per connection: org ID and user ID (parsed from the 'id' URL), instance_url, access_token, refresh_token, and issued_at. Encrypt tokens at rest.
- ALL REST calls go to {instance_url}/services/data/v68.0/... Never call login.salesforce.com, which returns URL_NOT_RESET.
- Refresh token rotation is on: after each refresh, atomically store the NEW refresh_token. Serialize refreshes per connection with a lock.
- Add a scheduled keep-alive that refreshes any connection idle 20+ days, because Salesforce expires refresh tokens idle for 30 days. Treat invalid_grant as 'needs reconnect' and notify the user.
- Map OAUTH_APPROVAL_ERROR_GENERIC and OAUTH_AUTHORIZATION_BLOCKED callback errors to a UI message telling the user their Salesforce admin must install our package (include INSTALL_URL from env).
- Handle API_DISABLED_FOR_ORG (edition lacks API access) and REQUEST_LIMIT_EXCEEDED (org's 24 h API allocation is shared with the customer's other integrations), and back off.
Deliverables:
1. /api/salesforce/connect route that builds the authorize URL (state + PKCE stored server-side) and /api/salesforce/callback route.
2. A SalesforceClient with query(soql), getRecord, updateRecord (PATCH /sobjects/{type}/{id}), and automatic refresh on 401.
3. Keep-alive job and tests (mock HTTP).
4. A metadata folder 'force-app/main/default' containing the ECA header (.eca) and OAuth settings (.ecaOauth) from the artifacts, plus sfdx-project.json for a 2GP managed package. Do NOT create or commit global OAuth settings or secrets.
Read config from the .env template. Don't hardcode secrets.Show bash
# Salesforce External Client App (consumer key/secret come from Setup > External Client App Manager > your app > OAuth Settings) SALESFORCE_CLIENT_ID=your-eca-consumer-key SALESFORCE_CLIENT_SECRET=your-eca-consumer-secret SALESFORCE_REDIRECT_URI=https://app.example.com/api/salesforce/callback SALESFORCE_SCOPES="api refresh_token id" SALESFORCE_API_VERSION=v68.0 # Default login hosts; per-connection override for My Domain SALESFORCE_LOGIN_URL=https://login.salesforce.com SALESFORCE_SANDBOX_LOGIN_URL=https://test.salesforce.com # Managed package install link shown to customer admins SALESFORCE_PACKAGE_INSTALL_URL=https://login.salesforce.com/packaging/installPackage.apexp?p0=04tXXXXXXXXXXXXXXX TOKEN_ENCRYPTION_KEY=generate-a-32-byte-random-key
Show xml
<?xml version="1.0" encoding="UTF-8"?>
<ExternalClientApplication xmlns="http://soap.sforce.com/2006/04/metadata">
<contactEmail>integrations@example.com</contactEmail>
<description>Lets the Example AI agent read and update Accounts and Opportunities.</description>
<distributionState>Packaged</distributionState>
<isProtected>false</isProtected>
<label>AI Agent Connector</label>
</ExternalClientApplication>Show xml
<?xml version="1.0" encoding="UTF-8"?>
<ExtlClntAppOauthSettings xmlns="http://soap.sforce.com/2006/04/metadata">
<commaSeparatedOauthScopes>Api, RefreshToken, OpenID</commaSeparatedOauthScopes>
<externalClientApplication>AiAgentConnector</externalClientApplication>
<label>AiAgentConnector_oauth</label>
</ExtlClntAppOauthSettings>
<!-- Callback URL, PKCE (isPkceRequired) and consumer credentials live in ExtlClntAppGlobalOauthSettings, which can't be packaged or committed; set them in Setup on the Dev Hub/PBO org. -->Show typescript
export async function exchangeCode(loginUrl: string, code: string, codeVerifier: string) {
const res = await fetch(`${loginUrl}/services/oauth2/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code,
code_verifier: codeVerifier,
client_id: process.env.SALESFORCE_CLIENT_ID!,
client_secret: process.env.SALESFORCE_CLIENT_SECRET!,
redirect_uri: process.env.SALESFORCE_REDIRECT_URI!,
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error}: ${body.error_description}`);
// body.instance_url is where ALL data API calls must go; body.id ends in /{orgId}/{userId}
const [orgId, userId] = new URL(body.id).pathname.split("/").slice(-2);
return { orgId, userId, instanceUrl: body.instance_url, accessToken: body.access_token, refreshToken: body.refresh_token };
}Why & details
The reasoning, evidence and sources behind everything above. Hover a badge to see its sources.
The full picture
Tenant-scoped
OAuth works against your own free Developer Edition org within about an hour, but serving other companies' orgs now means a packaged External Client App inside a second-generation managed package that each customer's admin installs. New connected apps have been blocked since Spring '26, uninstalled apps have been blocked for new users since September 2025, and refresh tokens idle for 30 days expire starting November 4, 2026 (production), so plan your packaging, the admin install step, and token keep-alive before you write any API code.
Each customer is a separate Salesforce org with its own instance URL (My Domain), admin-controlled access policies (permitted users, IP relaxation, refresh token policy) and edition-dependent API access. Since September 2025 an app must be installed in the customer's org before new users can authorize it. External Client Apps (the required replacement for connected apps) must be packaged and installed per org to work across orgs. You don't need Salesforce's approval to reach customers. The gate is each customer's admin, which is the tenant-scoped pattern rather than partner-gated.
Rating: Expect reviews, admin approvals or per-customer setup measured in days.
Free Developer Edition org, plus a local External Client App created in that same org with OAuth enabled, a callback URL, the api and refresh_token scopes, and PKCE. Works only for users of that one org.
A packaged ECA in a promoted second-generation managed package (registered namespace, Dev Hub, ideally a Partner Business Org) that each customer admin installs and configures. No Salesforce review is needed unless you list on AgentExchange or need Group/Professional Edition access, which adds a security review of unknown length.
What affects your setup
- Customer admin consent
Since September 2025, connected apps a System Administrator hasn't installed in the org are blocked for any new user. Only holders of the 'Approve Uninstalled Connected Apps' permission (auto-assigned to the standard System Administrator profile, not to cloned custom profiles) can bypass this. For a packaged ECA, the customer admin installs your managed package and owns the policies: permitted users (AllSelfAuthorized or AdminApprovedPreAuthorized plus profiles or permission sets), IP relaxation and refresh token policy.
- Per-customer setup
Every connection belongs to a specific org. Store instance_url per connection and call the data API there, because calls to login.salesforce.com fail. Pick the right login host: login.salesforce.com for production, test.salesforce.com for sandboxes, or the customer's My Domain. Each org needs your package installed and its own policy configuration. A local (unpackaged) ECA only serves the org it was created in.
- Paid plan required
The customer's org needs API access. It's on by default in Enterprise, Performance, Unlimited and Developer editions. Professional Edition needs a paid API add-on (otherwise API_DISABLED_FOR_ORG). Group and Professional Edition REST access for a third-party app requires passing security review and asking Salesforce to allowlist the app. Individual users also need the 'API Enabled' permission.
- Token lifecycle gotchas
Salesforce's security roadmap limits refresh-token idle time to 30 days: sandboxes from October 21, 2026, production from November 4, 2026. Using a token resets the clock. The customer admin's refresh token policy (Infinite, SpecificLifetime, SpecificInactivity, Zero) overrides your expectations. Partner apps must enable refresh token rotation, which can't be turned off once on, and must store each new refresh token. Developers report a cap of about 5 concurrent token pairs per user per app, with the oldest revoked first, and that a password change revokes all of the user's tokens. Access-token lifetime follows the session timeout, not a fixed number.
- Marketplace listing optional
AgentExchange (the current name for AppExchange in Salesforce's ISV docs) listing and its security review are required only to list publicly. They're also needed for GE/PE API allowlisting and partner benefits. A promoted (released) 2GP managed package version can be installed in production orgs from an install URL without being listed.
Before you start — why each matters
- Free Developer Edition org — Used to build and test. Sign up at developer.salesforce.com/signup. Developer Edition orgs can expire from inactivity, so don't use one as your long-term Dev Hub.
- Dev Hub plus registered namespace — Needed to build a second-generation managed package that carries your packaged ECA. Salesforce recommends a Partner Business Org (through the Salesforce Partner Program) as the Dev Hub, and says to define the ECA there because ECAs can't be created through Setup in scratch orgs.
- Customer org with API access — Enterprise, Performance, Unlimited or Developer edition, or Professional with the API add-on. The connecting user needs the 'API Enabled' permission and object permissions on Account and Opportunity.
- Customer admin who can install packages — A System Administrator installs your managed package and sets the ECA policies (permitted users, IP relaxation, refresh token policy).
- HTTPS callback URL and fixed egress IPs — Callback URL for the web-server flow. Partner apps must also enable the Refresh Token IP Allowlist (at most 256 addresses across all ranges), so refresh from stable egress IPs.
How well this guide is backed
Step details
Create a free Developer Edition org to build and test in. Don't build in a customer's production org.
👤 Why you: Needs your logged-in console session (2FA/CAPTCHA)
🤖 What an agent can do: Draft the signup details and a checklist. A person has to submit the form and verify the email.
https://developer.salesforce.com/signup ↗Decide where your packaged ECA will live. The recommended route is a Partner Business Org, through the Salesforce Partner Program, used as Dev Hub, with 2GP enabled and a namespace registered in a separate Developer Edition org and linked to it. A Developer Edition Dev Hub works for experiments, but packages tied to it can't be updated once it expires.
👤 Why you: A product/business judgement only you can make
🤖 What an agent can do: Generate sfdx-project.json with the namespace and run 'sf org login web --set-default-dev-hub' once a person has logged in.
https://partners.salesforce.com/ ↗In the Dev Hub/PBO org, go to Setup > External Client App Manager > New. Set Distribution State to Packaged, enable OAuth, add your HTTPS callback, and select the scopes Api, RefreshToken and optionally OpenID. Turn on 'Require PKCE'. Also turn on refresh token rotation, the 30-day idle refresh TTL and the refresh-token IP allowlist, which Salesforce requires of partner apps used by more than two customer production orgs (deadline May 11, 2026). Then copy the consumer key and secret. They live in global OAuth settings, which are never packaged.
👤 Why you: Needs your logged-in console session (2FA/CAPTCHA)
🤖 What an agent can do: Author the ExternalClientApplication (.eca) and ExtlClntAppOauthSettings (.ecaOauth) metadata and deploy them with 'sf project deploy start'. The person copies the consumer key and secret from Setup into your secret store.
https://login.salesforce.com/ ↗Build the authorize URL on login.salesforce.com, test.salesforce.com or the customer's My Domain, with code_challenge_method=S256. Exchange the code with client_secret and code_verifier. Persist access_token, refresh_token, instance_url and the id URL (org ID) per connection. On every refresh, store the new rotated refresh token atomically.
🤖 What an agent can do: Write the OAuth routes, an encrypted token store keyed by org ID and user ID, a refresh mutex to avoid rotation races, and a client that always uses instance_url plus /services/data/v68.0.
https://login.salesforce.com/.well-known/openid-configuration ↗Create the package and a version with code coverage (promotion needs 75% if the package contains Apex), then promote it to released so production orgs can install it. Promotion can't be undone.
🤖 What an agent can do: Run 'sf package create --package-type Managed', then 'sf package version create --code-coverage --installation-key-bypass', then 'sf package version promote'. Capture the 04t install ID and build the install URL.
https://resources.docs.salesforce.com/latest/latest/en-us/sfdc/pdf/pkg2_dev.pdf ↗Complete the flow as your own user and run a SOQL query against Account and a PATCH against an Opportunity. This proves the code before you take on packaging.
👤 Why you: Needs your logged-in console session (2FA/CAPTCHA)
🤖 What an agent can do: Write an integration test script for SELECT Id, Name FROM Account LIMIT 5 and PATCH /sobjects/Opportunity/{id}. A person clicks through the consent screen once.
https://login.salesforce.com/services/oauth2/authorize ↗Install the package into a separate Developer Edition org and connect a user from that org. If you see OAUTH_AUTHORIZATION_BLOCKED 'Cross-org OAuth flows are not supported for this external client app', the installed ECA isn't linked to your global OAuth settings. Fix this before any customer touches it.
👤 Why you: Needs your logged-in console session (2FA/CAPTCHA)
🤖 What an agent can do: Script the install with 'sf package install' and re-run the integration test against the second org. Capture the error payload if it fails.
Do this only if you want a public listing, Group/Professional Edition REST access, or partner benefits. It requires Partner Program membership and a security review submission (test environments plus documentation). The timeline isn't published.
👤 Why you: Waiting on the provider's reviewers
🤖 What an agent can do: Run Salesforce Code Analyzer (sf code-analyzer run --rule-selector AppExchange --rule-selector Recommended:Security) and draft the security review documentation.
https://partners.salesforce.com/ ↗Give customers the package install URL and step-by-step instructions: which profiles or permission sets to grant, the recommended policies, and how to choose production vs sandbox login.
🤖 What an agent can do: Generate the admin guide and an in-app 'Connect Salesforce' screen with a production/sandbox/My Domain selector.
The admin installs the package and opens the External Client App's policies. They choose Permitted Users (AdminApprovedPreAuthorized plus a permission set is the common enterprise choice), IP relaxation, and the refresh token policy. They also make sure connecting users have API Enabled and Account/Opportunity edit rights.
👤 Why you: Your customer's admin must act
🤖 What an agent can do: Pre-fill a permission set definition in the package, for example 'AI Agent Connector User', so the admin only has to assign it.
Users click Connect and approve the scopes. Your backend refreshes each connection at least every few weeks so it never sits idle for 30 days, and treats invalid_grant as 'reconnect needed'.
👤 Why you: Your customer's admin must act
🤖 What an agent can do: Add a scheduled job that refreshes tokens idle for 20 days or more, plus alerting and a reconnect email when refresh fails.
Gotchas explained
- BlockerOld tutorials say 'create a connected app' — you can't anymore
As of Spring '26, Salesforce blocks connected app creation in the UI and the Metadata API. Support can enable it on request, but Salesforce says that option will go away, and connected apps reach end of support in Summer '27.
Fix: Build on an External Client App from day one. Migrate any existing connected app before Summer '27.
- BlockerA local ECA only serves its own org
Developers report that using a local ECA's consumer key with users from other orgs fails with OAUTH_AUTHORIZATION_BLOCKED, 'Cross-org OAuth flows are not supported for this external client app'. Connected apps never had this limit.
Fix: Set Distribution State to Packaged and ship the ECA in a managed package, or deploy the ECA metadata into each customer org. Test with a second org before launch.
- WarningUninstalled apps are blocked for new users (since Sept 2025)
Users in an org where your app isn't installed get blocked. The commonly reported error is OAUTH_APPROVAL_ERROR_GENERIC. Only users with 'Approve Uninstalled Connected Apps' get through. Device-flow apps are blocked even for users who authorized them earlier.
Fix: Make the admin install step part of onboarding. Detect this error and show 'Ask your Salesforce admin to install <app>' along with the install link.
- WarningRefresh tokens die after 30 idle days (Nov 4, 2026 in production)
An agent that touches a quiet customer once a month or less will find its refresh token invalidated. Each use resets the 30-day window.
Fix: Run a keep-alive refresh for every connection at least every 20–25 days. Alert on invalid_grant and prompt the user to reconnect.
- WarningRotation races and silent revocations
With refresh token rotation, the old token is revoked as soon as it's used, so parallel workers that refresh at the same time knock each other out. Tokens are also revoked when the user changes their password, when the admin revokes the app, or (developers report) when more than about 5 token pairs exist for a user and app.
Fix: Serialize refreshes per connection behind a lock, persist the new refresh token before using the access token, and reuse an existing grant instead of re-running OAuth repeatedly.
- WarningProfessional/Group Edition customers can't use the API
Without the API add-on, Professional Edition returns API_DISABLED_FOR_ORG. Group and Professional Edition REST access for third-party apps requires a passed security review plus allowlisting by Salesforce.
Fix: Check the customer's edition during onboarding and explain the add-on path, or go through security review if smaller editions matter to you.
- WarningA Developer Edition Dev Hub can strand your package
If the Dev Hub that owns your 2GP package expires (Developer Edition orgs can expire from inactivity), installed packages can't be updated and new installs may fail.
Fix: Use a Partner Business Org as the Dev Hub for anything customers will install.
- InfoAPI calls to login.salesforce.com fail
The REST API lives on each org's instance (My Domain), not the login host. Calling login.salesforce.com returns 400 URL_NOT_RESET.
Fix: Always build API URLs from the instance_url returned with the token.
Why each scope
| Scope | Why you need it | Tier | Evidence |
|---|---|---|---|
api | Query and update Accounts, Opportunities and other records through the REST API, acting as the connecting user. Access is bounded by that user's profile, permission sets and sharing rules. | sensitive | |
refresh_token | Get a refresh token so the agent can act while the user is away. offline_access is a synonym. | basic | |
id | Optional. Gets the identity URL (org ID and user ID) so you can key connections by org. openid works too if you want an ID token. | basic |
Reference facts
- Login hostslogin.salesforce.com (production and Developer Edition), test.salesforce.com (sandboxes), or the org's https://MyDomainName.my.salesforce.com. Every host serves the same /services/oauth2/* paths.
- PKCEOnly S256 is advertised. Partner apps must turn PKCE on, and it can't be disabled afterwards. Confidential clients send both code_verifier and client_secret.
- Refresh tokensReturned only if the app has the RefreshToken scope and you request refresh_token (or offline_access). Lifetime comes from the customer admin's refresh token policy. A 30-day idle limit applies from Nov 4, 2026 in production (Oct 21 in sandboxes).
- Access token lifetimeNot fixed. It follows the session timeout (an org or app policy), so on 401 INVALID_SESSION_ID, refresh and retry.
- Call the instance, not loginUse the instance_url from the token response, e.g. https://MyDomainName.my.salesforce.com/services/data/v68.0/ (v68.0 is Winter '27).
- API limitsEnterprise edition: 100,000 calls plus 1,000 per Salesforce license per org per 24 h (shared with all of the customer's other integrations). Developer Edition: 15,000 per 24 h. Long-running (20 s or more) concurrent requests: 25 in production, 5 in Developer Edition.
- Client authenticationclient_secret_post, client_secret_basic, private_key_jwt and tls_client_auth are supported. DPoP signing algorithms are advertised. Discovery also lists mcp_api and a2a_api scopes (Salesforce-hosted MCP and agent-to-agent).
- Connected apps vs ECAsNew connected apps can't be created in the UI or the Metadata API as of Spring '26. Support can still enable creation, but only temporarily. Connected apps reach end of support in Summer '27, so build on External Client Apps.
- PKCE (from discovery document)Advertised methods: S256
- Scopes advertised in discoverycdp_ingest_api, custom_permissions, cdp_segment_api, content, cdp_api, chatbot_api, cdp_identityresolution_api, interaction_api, wave_api, web, cdp_calculated_insight_api, einstein_gpt_api …
- Endpoints observed liveAuthorize: HTTP 400; error "invalid_client_id"; → endpoint is live and rejects the unknown client · Token: HTTP 400; error "invalid_client_id: client identifier invalid"; → token endpoint is live and rejects a bogus code
What we verified — and what we couldn't
Live probes (no credentials)
- ✓discovery
https://login.salesforce.com/.well-known/openid-configurationHTTP 200; issuer https://login.salesforce.com; authorize https://login.salesforce.com/services/oauth2/authorize; PKCE methods: S256[P1] - ✓authorize
https://login.salesforce.com/services/oauth2/authorizeHTTP 400; error "invalid_client_id"; → endpoint is live and rejects the unknown client[P2] - ✓token
https://login.salesforce.com/services/oauth2/tokenHTTP 400; error "invalid_client_id: client identifier invalid"; → token endpoint is live and rejects a bogus code[P3] - ✓page
https://login.salesforce.com/HTTP 200; title "Login | Salesforce"[P4] - ✓page
https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm&type=5HTTP 301; redirects to help.salesforce.com/s/articleView[P5]
Open questions
- What exact configuration lets a packaged ECA authorize users in subscriber orgs using your single consumer key?Official docs say a distributed ECA either references the source org's global OAuth settings or generates new ones in the subscriber org. A 2026 Trailblazer thread shows a packaged ECA still failing cross-org, and nobody posted a confirmed fix. The help.salesforce.com ECA pages didn't render for us.To resolve: Install your promoted package into a second Developer Edition org and test before launch. Check the installed ExtlClntAppOauthSettings OAuth link, and open a Partner Support case if it fails.
- Does the 30-day idle refresh-token limit apply to every app automatically, or only when the 'Limit Idle Refresh Token TTL' option is on?The security roadmap (published Oct 7, 2026) lists it as an enforced change with sandbox and production dates. The ISVforce Guide describes it as a checkbox partners turn on. The two docs read differently.To resolve: Read the Winter '27 release notes and test in a sandbox after October 21, 2026 by leaving a token idle. Design for the 30-day limit either way.
- Do the partner security controls (PKCE, rotation, idle TTL, IP allowlist; due May 11, 2026) bind a vendor that isn't in the Salesforce Partner Program?The ISVforce Guide applies them to any connected app or ECA 'used in connection with a Partner Application' in more than two customer production orgs, with suspension as the penalty. Whether a non-partner counts as a 'Partner' isn't spelled out.To resolve: Enable all four controls anyway, since they're good practice and cheap. Confirm scope with Salesforce partner support if you won't join the program.
- Could the advertised dynamic client registration endpoint (/services/oauth2/register) replace per-org packaging?Discovery advertises registration_endpoint, and also mcp_api and a2a_api scopes. We couldn't find docs saying third-party apps may self-register in arbitrary customer orgs. It's likely scoped to Salesforce-hosted MCP clients.To resolve: Find the Salesforce hosted MCP server docs on dynamic registration and test against a Developer Edition org. Don't rely on it for production until it's documented.
Ask the provider
A ready-to-send message built from the open questions above.
- Send to
- No contact channel found — check https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm&type=5 for developer support
- Subject
- OAuth integration questions — Salesforce
Hi Salesforce developer support team, We're building an integration where AI agent reads and updates CRM records (accounts, opportunities) in each customer's Salesforce org. Before we register an OAuth app and launch to customers, we couldn't find answers to the following in your documentation: 1. What exact configuration lets a packaged ECA authorize users in subscriber orgs using your single consumer key? (What we found: Official docs say a distributed ECA either references the source org's global OAuth settings or generates new ones in the subscriber org. A 2026 Trailblazer thread shows a packaged ECA still failing cross-org, and nobody posted a confirmed fix. The help.salesforce.com ECA pages didn't render for us.) 2. Does the 30-day idle refresh-token limit apply to every app automatically, or only when the 'Limit Idle Refresh Token TTL' option is on? (What we found: The security roadmap (published Oct 7, 2026) lists it as an enforced change with sandbox and production dates. The ISVforce Guide describes it as a checkbox partners turn on. The two docs read differently.) 3. Do the partner security controls (PKCE, rotation, idle TTL, IP allowlist; due May 11, 2026) bind a vendor that isn't in the Salesforce Partner Program? (What we found: The ISVforce Guide applies them to any connected app or ECA 'used in connection with a Partner Application' in more than two customer production orgs, with suspension as the penalty. Whether a non-partner counts as a 'Partner' isn't spelled out.) 4. Could the advertised dynamic client registration endpoint (/services/oauth2/register) replace per-org packaging? (What we found: Discovery advertises registration_endpoint, and also mcp_api and a2a_api scopes. We couldn't find docs saying third-party apps may self-register in arbitrary customer orgs. It's likely scoped to Salesforce-hosted MCP clients.) Could you point us to the right documentation or process — including whether any review or approval is needed before customers outside our own account can connect, and the typical timeline? Thanks, [Your name] [Company · website]
Sources
- S1New connected apps can no longer be created in Spring '26 (Salesforce Help knowledge article 005228017)official
- S2Prepare for Salesforce Connected App Usage Restrictions Change (Salesforce Help knowledge article 005132365)official
- S3Salesforce security roadmap: OAuth security requirements and connected app end of support (knowledge article 005461287)official
- S4REST API Developer Guide, Version 68.0 Winter '27 (PDF)official
- S5Salesforce Developer Limits and Allocations Quick Reference (PDF)official
- S6ISVforce Guide: Build and Distribute AgentExchange Solutions, Version 68.0 (PDF) — 'Secure Your Connected Apps and External Client Apps', GE/PE API access, security reviewofficial
- S7Second-Generation Managed Packaging Developer Guide, Version 68.0 (PDF)official
- S8Metadata API Developer Guide (PDF) — ExternalClientApplication, ExtlClntAppOauthSettings, ExtlClntAppGlobalOauthSettings, ExtlClntAppOauthConfigurablePoliciesofficial
- S9Mobile SDK Development Guide (PDF) — OAuth 2.0 Refresh Token Flowofficial
- S10Trailblazer Community: Packaged External Client App — subscriber OAuth blocked with 'Cross-org OAuth flows are not supported'community
- S11Unified.to: Salesforce External Client Apps on multiple organizationscommunity
- S12Paragon: Salesforce Connected App changescommunity
- S13Nango: Salesforce OAuth refresh token invalid_grant — what it means and how to fix itcommunity
- T1Probe: GET https://login.salesforce.com/.well-known/openid-configuration (200; S256 only, refresh_token/offline_access/api/mcp_api scopes, private_key_jwt, DPoP)probe
- T2Probe: GET authorize with client_id=probe-invalid → HTTP 400, body error=invalid_client_id&error_description=client identifier invalid (no redirect)probe
- T3Probe: POST token endpoint with bogus code/client → HTTP 400 {"error":"invalid_client_id","error_description":"client identifier invalid"}probe
- T4Probe: GET https://login.salesforce.com/services/data/ → HTTP 400 URL_NOT_RESETprobe
- T5Probe: GET https://test.salesforce.com/.well-known/openid-configuration → 200, issuer https://test.salesforce.comprobe
- P1Our probe: discovery check on login.salesforce.comprobe
- P2Our probe: authorize check on login.salesforce.comprobe
- P3Our probe: token check on login.salesforce.comprobe
- P4Our probe: page check on login.salesforce.comprobe
- P5Our probe: page check on help.salesforce.comprobe