Skip to content

Client Credentials

Module 3 of 6 in the chapter OAuth: The Base Pattern, chapter 8 of Securing Salesforce: Identity and Access. Each module stands on its own.

The question this module answers: What does a program present at the entrance today, and what comes back?

In module 2, a person’s password went to the entrance. Now substitute it. Take out the person’s username and password, and put in the program’s own credentials: the client ID and the secret of its app. That’s the client credentials flow.

Salesforce describes it as “a more secure alternative to the OAuth 2.0 username-password flow” (S1). Same two steps, same entrance, same stall. Only one card in the picture has changed.

Client credentials: the same shape, the current form The same three columns. Step 1: the client holds its client ID and secret, from its external client app, and presents them at the entrance with grant_type=client_credentials; the entrance, on your My Domain, runs as the integration user you chose, and gives back the wristband: the access token, the instance URL and the scope. Step 2: the client shows the wristband at the stall, which serves what the integration user may see. Footnote: no person's password anywhere, and no re-entry pass; when the wristband runs out, the program goes back to the entrance. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.58.0", "built": "2026-11-04", "id": "DGM-IAM-OF-03", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "cells 0.5.0", "theme": "stevetecharc 1.4.0"} THE CLIENT THE ENTRANCE: SALESFORCE'S TOKEN ENDPOINT THE STALL: AN API 1. Goes to the entrance grant_type=client_credentials: its client ID and secret, from its external client app The entrance on your My Domain; runs as the integration user you chose; answers with the access token, instance URL and scope 2. Goes to the stall shows the wristband on every call The stall serves what the integration user may see client ID + secret the wristband the wristband the data No person's password anywhere, and no re-entry pass: when the wristband runs out, the program goes back to the entrance. HOW TO READ IT the entrance: where you prove who you are, once © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

Integration Architect teaches this flow from the integration’s side: setting it up step by step in its chapter 4, and the integration user in its chapter 13. Here we read the protocol: what goes in, what comes out, and what each part means.

The client posts to the token endpoint on your My Domain (S1):

POST /services/oauth2/token HTTP/1.1
Host: MyDomainName.my.salesforce.com
grant_type=client_credentials&
client_id=*******************&
client_secret=*******************
  • grant_type=client_credentials names the flow.
  • client_id is the app’s consumer key, and client_secret its consumer secret, both from the app’s settings in External Client App Manager (S1).

Three details trip people up.

My Domain only. “For this flow, requests to https://login.salesforce.com (opens in a new tab) and https://test.salesforce.com (opens in a new tab) aren’t supported. Use your My Domain URL instead” (S1). Old scripts that send everything to login.salesforce.com fail here.

Body or header. The ID and secret can go in the body, as above, or “for added security”, in a Basic authorization header, the two joined with a colon and Base64-encoded (S1). Never in the address: “Don’t use GET parameters in the URL query string to pass sensitive information” (S1).

No scopes in the request. “Because Salesforce doesn’t support scopes on the token endpoint, you can’t include scopes in the request. Instead, assign scopes to your external client app” (S1). The app decides what the wristband allows, not the caller. Module 4 is about that.

If the entrance accepts the credentials, it answers in JSON (S1):

{
"access_token": "*******************",
"instance_url": "https://yourInstance.salesforce.com",
"id": "https://login.salesforce.com/id/00Dx00000000001/005x00000000001",
"token_type": "Bearer",
"scope": "id api",
"issued_at": "1762272000000",
"signature": "*******************"
}

Read it field by field:

FieldWhat it is
access_tokenThe wristband. Shown on every call to the stall
instance_urlWhere the stall is: the address to send API calls to
idAn identity URL naming the org and the integration user: …/id/orgID/userID
token_typeBearer: whoever holds it can use it, so treat it like the access it is
scopeWhat kinds of access the wristband carries, from the app (module 4)
issued_atWhen it was issued, in milliseconds
signatureA signature made with the client secret, so the client can check the id URL hasn’t changed

What’s not in the answer matters too. There’s no refresh token: “This flow doesn’t support refresh tokens” (S1). When the wristband runs out, the program goes back to the entrance with its ID and secret and gets a new one. It doesn’t need a re-entry pass, because it never needed a person.

A token has to be someone’s. In the username-password flow it was the person whose password was sent. In client credentials there’s no person, so you choose one: the flow “does require you to specify an integration user to run the integration” (S1). In the app’s policies, you enable the flow and enter “the execution user’s username” (S8).

Everything the program does is done as that user. Every record it creates or changes shows that user. And it reaches what that user may see, and nothing more.

So who should that user be? I always ask the room: if the integration user can see everything, what can the program see? Everything. And if it’s a trading app, would you want one customer’s program seeing another customer’s money? You would not. Salesforce recommends “one Salesforce user for every integration”, with the Salesforce Integration license and the Minimum Access - API Only Integrations profile (S11). Chapter 5, module 4 asked whether you should use an integration user at all; Integration Architect chapter 13, module 4 is the whole argument for one integration, one identity.

Here’s the warning Salesforce puts at the top of this flow’s page: “With this flow enabled, any person or app that has access to your external client app’s consumer key and consumer secret can get an access token” (S1).

Read that again with the food festival in mind. There’s no person to check, no MFA, no login screen. The ID and secret are the proof. Whoever has them can walk to the entrance and get a wristband for the integration user.

So the secret is treated like a password, because it is one: kept in a secret store, never in code or a chat, changed on a schedule, and changed at once if it leaks (S1, S8). Integration Architect chapter 13, module 8 covers where secrets live.

In External Client App Manager: edit the app’s settings, enable OAuth, choose its scopes, and select Enable Client Credentials Flow; then edit its policies, enable the flow there too, and enter the execution user (S8, S9). The practice at the end of this chapter walks it, with a narrow scope on purpose.

Module 4: what the wristband lets you do, the scopes.

  • Which integrations use client credentials: a program with no person there, acting as its own user.
  • The execution user for each one, with only the access it needs.
  • Where the client secret lives, who can read it, and how it’s changed.
  • That every token request goes to your My Domain, not login.salesforce.com.