Salesforce
www.salesforce.com/ ↗OAuth works self-serve in minutes via an External Client App in Setup — Connected Apps now need a Salesforce Support ticket to re-enable creation — but there is no global app registration, so every customer org's admin must install and pre-authorize your app before the agent can act for their users.
01Pick your path
02Time & effort
- DEVCreate app in Setup15–30 minutessourced[S4][S1]Setup > App Manager > New External Client App; Connected App only if you must.
- DEVEnable OAuth, callback, scopes5–15 minutessourced[S4][S1]Click Enable OAuth, set callback URL, tick api and refresh_token/offline_access (web only for browser apps).
- DEVSet token policies5–10 minutessourced[S1][S4]Refresh token expiry 90 days or less, session timeout 15 minutes.
- DEVCopy consumer key/secret5–10 minutessourced[S4]Email verification code required — developer must be present.
- DEVBuild authorize + token exchange + refresh2–4 hoursinferred[S2]Endpoints confirmed by probe; code volume is small, testing in a sandbox org is the variable.
- PRODCustomer admin install + pre-authorizewait 1–5 daysinferredPer customer org; the waiting party is each org's Salesforce admin, not Salesforce itself.
03Steps
Get a working connection
Connected Apps are deprecated and creation is off by default; External Client Apps are the preferred framework and are self-serve. Only pick a Connected App for Dev Hub scratch-org/sandbox flows or an app that already exists.
“Otherwise, create an external client app, which is the preferred integration framework.” — [S1] verified verbatim
↗ developer.salesforce.com/docs/platform/sfdx-dev/guide/sfdx-dev-auth-eca.html◆ prepared by agent · App-type decision noteDecision: External Client App (not Connected App). Reason: connected-app creation is disabled by default as of Spring '26 and requires a Salesforce Support ticket to enable an org permission; External Client Apps are the supported path and are self-serve.
Setup > Quick Find 'App Manager' > App Manager > New External Client App. Fill in the name and your contact email. This must be done by someone logged into the org.
“From the Quick Find box in Setup, enter App Manager, then click App Manager.” — [S4] verified verbatim
Under 'API (Enable OAuth Settings)' click Enable OAuth; set the Callback URL to your agent's HTTPS redirect (http://localhost:1717/OauthRedirect while testing); tick api and refresh_token/offline_access, and web only if a browser is involved.
“Under API (Enable OAuth Settings), click Enable OAuth.” — [S4] verified verbatim
Policies tab: set 'Expire refresh token after' 90 days (or less) and Session Timeout 15 minutes. For JWT, set Permitted Users to 'Admin approved users are pre-authorized' and assign profiles/permission sets.
“In the Refresh Token Validity Period box, enter 90. For Refresh Token Validity Unit, select Day(s).” — [S4] verified verbatim
App Manager > External Client App Manager > your app > Settings > OAuth Settings > Consumer Key and Secret. Enter the emailed verification code, then copy both values into your secret store. The agent cannot do this step.
“Open OAuth Settings and click Consumer Key and Secret.” — [S4] verified verbatim
- Implement authorization-code flow against the probed endpointsagentinferred
Redirect to /services/oauth2/authorize with client_id, response_type=code, redirect_uri; exchange the code at /services/oauth2/token. A 400 'invalid_client_id' at the authorize step means the app record or host is wrong — the probe confirms that error is the signature of a missing app.
◆ prepared by agent · Token exchange + refresh against the probed endpointsPOST https://login.salesforce.com/services/oauth2/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=<code from callback> &client_id=<CONSUMER_KEY> &client_secret=<CONSUMER_SECRET> &redirect_uri=https%3A%2F%2Fyour-agent.example.com%2Foauth%2Fcallback # refresh POST https://login.salesforce.com/services/oauth2/token grant_type=refresh_token&refresh_token=<rt>&client_id=<KEY>&client_secret=<SECRET> # sandbox: swap host to https://test.salesforce.com
Make it production-ready
Refresh before the 15-minute session timeout; when the 90-day refresh token expires, send the user back through /services/oauth2/authorize. Don't build a silent-retry loop that fails forever.
“To continue running CLI commands against an org whose refresh tokens have expired, reauthorize it with the org login web or org login jwt command.” — [S4] verified verbatim
For an unattended agent: enable JWT bearer flow, upload a certificate, set pre-authorized profiles/permission sets, and use 'you@org' style subject logins. You must rotate the certificate before it expires (expiry handling is inferred).
“_(Required for JWT)_ In the Flow Enablement section, select Enable JWT Bearer Flow.” — [S4] verified verbatim
- Package and hand off to each customer orgagentinferred
If other orgs will use your agent, each admin installs the app, sets the refresh-token policy, and pre-authorizes users. Ship a one-page admin checklist — the agent can draft it; the admin click-through is theirs.
04Requirements, scopes & nuances
You'll need
- ▸Salesforce org with Setup access (admin) to create an External Client App or Connected App. inferred[S1][S4]
- ▸Consumer Key (client_id) and, for the web server flow, Consumer Secret — plus email access to pass the verification-code gate. sourced ❝[S1][S4]
- ▸A registered callback URL (the CLI guide uses http://localhost:1717/OauthRedirect for local testing; use your own HTTPS redirect in an agent). sourced ❝[S4]
- ▸For JWT/headless: a digital certificate (server.crt) uploaded to the app and profiles/permission sets marked pre-authorized. sourced ❝[S4][S1]
- ▸For Connected Apps specifically: a Support-enabled org permission and the admin toggle 'Allow creation of connected apps'. sourced ❝[S1]
Gotchas
- !The OAuth scopes are chosen on the app record (api / web / refresh_token, offline_access), not requested at authorize time, so scope minimization is a Setup decision you make once per app. inferred
- !The discovery document's scopes_supported does NOT list api, web, or refresh_token — it lists CDP/Chatter/Wave/Einstein scopes instead — so don't build your scope allow-list from the probe output; use the app's OAuth Scopes checkboxes. inferred
- !Refresh tokens are capped: both guides recommend 'Expire refresh token after' 90 days or less, so any agent running longer than that needs a reauthorization path, not just a refresh loop. sourced ❝[S1][S4]
- !Access-token session timeout is set on the app (15 minutes in the Salesforce CLI guide); your agent must refresh proactively rather than assume a long-lived access token. sourced ❝[S1][S4]
- !Sandbox and production are different issuers and endpoints (test.salesforce.com vs login.salesforce.com); credentials and callbacks must be registered against the right one. inferred
- !Connected Apps are deprecated and being replaced by External Client Apps; building new on Connected Apps means a Support dependency you can avoid. sourced ❝[S1][S2][S4]
| Scope / permission | Tier | Note | Evidence |
|---|---|---|---|
| api | basic | 'Manage user data via APIs (api)'. The one you actually need for REST/SOQL work. | sourced ❝[S4][S1] |
| refresh_token / offline_access | sensitive | 'Perform requests at any time'. Grants long-lived access — treat as sensitive and pair with the 90-day expiry policy. | sourced ❝[S4][S1] |
| web | basic | 'Manage user data via Web browsers (web)'. Only needed if the agent's flow involves browser-based login; drop it for pure server-side exchange if your flow allows. | sourced ❝[S4][S1] |
| einstein_gpt_api, wave_api, chatbot_api, cdp_* | gated | Present in scopes_supported on both hosts, but nothing in these sources explains their requirements. Assume product licenses and org provisioning are needed before they can be granted (inferred). | inferred |
05If you get blocked
→ You complete it once when you copy the Consumer Key/Secret, then store both in your secret manager and feed them to the agent's config.
→ You need Setup access (System Administrator or delegated admin) in the target org; if it's a customer's org, their admin creates/installs the app and reads out the consumer key to you.
→ Use an External Client App instead (fully self-serve), or have an admin open Setup > External Client Apps > Settings and turn on 'Allow creation of connected apps' once Support has enabled the org permission.
→ You assign profiles/permission sets in the app's Policies tab; the agent can draft which permission sets are needed but cannot grant them.
→ Design for per-org configuration (each tenant supplies its own consumer key or installs your package) rather than one global client_id; start with one pilot org.
06Evidence: what was tested, sourced, and still uncertain
Sources read
- [S1] Salesforce Developers official
- [S2] Salesforce Developers official
- [S3] Sitemap official
- [S4] Salesforce Developers official
- [composio] Composio — Managed OAuth apps directory official
- [probe] Live HTTP probes run by the agent (dummy client_id, no credentials) probe
Still uncertain
- ? No source covers distribution mechanics or AppExchange security-review timelines, so the 'package to customer orgs' path and its wait are inferred.
- ? The discovery document's scopes_supported omits api/web/refresh_token, which contradicts the Setup-guided scope list; the authoritative scope set is the app record, per the sourced guides.
- ? No source describes the user-consent screen contents or whether end users see per-scope consent, so what your users actually approve is unknown.
- ? API rate limits, edition/licence requirements, and My Domain vs login.salesforce.com login hosts are not covered by these sources — treat host choice beyond the two probed issuers as inferred.
- ? Nothing here documents Salesforce's own review of third-party apps at the OAuth layer; the provider-side gate in practice is each customer org's admin, not Salesforce.
- ? The two time estimates for building the flow and for customer-side rollout are judgement calls, not sourced figures.
- ? Generated automatically; no app was registered and no review was submitted.