Skip to content

Secrets

Module 8 of 8 in the chapter Trust, Identity, and Integration Security, chapter 13 of the Integration Architect course. Each module stands on its own. Previous: Tokens as a Design Decision · Back to the chapter: Trust, Identity, and Integration Security

The question this module answers: Where do an integration’s secrets belong, where must they never be, and how do you practise with them safely?

Remember the partner door from module 3? An attacker used a vendor’s stolen tokens to export data from many orgs. Then they did something that tells you exactly what they were after. They searched the stolen records for secrets: “sensitive credentials such as Amazon Web Services (AWS) access keys (AKIA), passwords, and Snowflake-related access tokens” (Widespread Data Theft Targets Salesforce Instances via Salesloft Drift (opens in a new tab), Google Threat Intelligence, August 26, 2025, checked 2026-11-07).

Why would those be in CRM records? Because someone pasted them there. An admin troubleshooting an integration put the key in a case comment. A developer left a password in a description field so the next person could find it. The ordinary CRM data was bad enough to lose. The secrets inside it opened the next door.

Don’t create a really strong locked door and then leave the back door open. Everything in this chapter, the identities, the flows, the tokens, is the locked door. Where the secrets sit is the back door.

Where secrets live, and where they never go Where secrets live, and where they never go: two panels. Where secrets live, places built to hold them: Salesforce's named and external credentials; the other system's own secret store; on your bench, a local vault, never synced; each with an owner and a rotation date. Where they never go, places never meant to hold them, in coral: a record, such as a description, a note or a case comment; code, a flow, or a file in source control; an email, a chat message or a ticket; an AI tool's prompt. Underneath: if a secret has been somewhere it shouldn't, it's been seen; rotate it, then remove it. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.58.0", "built": "2026-11-03", "id": "DGM-INT-TW-16", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "comparison/side-by-side 0.5.0", "theme": "stevetecharc 1.4.0"} Where secrets live places built to hold them Salesforce's named and external credentials. The other system's own secret store. On your bench: a local vault, never synced. Each with an owner and a rotation date. Where they never go places never meant to hold them A record: a description, a note, a case comment. Code, a flow, or a file in source control. An email, a chat message or a ticket. An AI tool's prompt. If a secret has been somewhere it shouldn't, it's been seen. Rotate it, then remove it. © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

A few right homes, all built for it; many wrong ones, none of them meant for it.

Places built to hold them:

  • Salesforce’s named and external credentials, for every secret Salesforce uses to call out. The external credential keeps it encrypted, and only the people and processes you allow can use it (chapter 4).
  • The other system’s own secret store, for the client ID and secret it uses to call in: the integration layer’s vault, a cloud’s secret manager. Never its configuration file.
  • On your own bench, a local vault. Postman’s, in the lab below, is one.

And each secret gets an owner and a rotation date, like every certificate in chapter 12.

Places never meant to hold them: a record, any field, any note, any comment; code, a flow, or a file in source control; an email, a chat message or a ticket; and an AI tool’s prompt.

That last one is new, and it matters more every month. Never paste a secret into an AI tool. Not to debug a failing callout, not to ask why a token was refused. Give it the error, the request with the secret replaced by a placeholder, the configuration without the values. An AI doesn’t need your secret to help you, and once it’s in a prompt, you don’t control where it goes.

If a secret has been somewhere it shouldn’t, assume it’s been seen. Then the order matters:

  1. Rotate it first. Issue a new secret, put it where it belongs, and confirm the integration works with it.
  2. Revoke what it gave out. Every token the old secret produced, at /services/oauth2/revoke (module 7).
  3. Then remove it from the record, the file, the message. Removing it first only hides that it leaked.
  4. Then look at what it was used for while it was out (chapter 14).

And go looking before anyone else does. Search your own records for the shapes secrets take: AKIA, password, secret, token, Bearer. You may be surprised what’s there.

Now practise it, safely. In 2023 I showed the Postman demo with the username-password flow. That flow retires on February 20, 2027, so here’s the bench rebuilt: two External Client Apps, the two current flows, and no password anywhere except Salesforce’s own login page.

Your lab bench: two flows from Postman Your lab bench, two flows from Postman: five numbered steps, with why beside each. 1, create the External Client Apps, one for each flow, in your Developer Edition org: one app per caller, even on a bench. 2, put the consumer key and secret in the vault, Postman's local vault, never synced: the secret never sits in a request, a file or a chat. 3, client credentials, a POST to your My Domain token address: no person, so the token runs as the app's integration user. 4, the web server flow with PKCE, where Postman opens the browser and you sign in at Salesforce: you type your password only into Salesforce. 5, highlighted, call the REST API with each token, then revoke: compare who each call ran as, then take both tokens back. Underneath: no username-password flow anywhere; it retires on 20 February 2027. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.58.0", "built": "2026-11-03", "id": "DGM-INT-TW-17", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "flow/sequence 0.1.0", "theme": "stevetecharc 1.4.0"} Create the External Client Apps one for each flow, in your Developer Edition org One app per caller, even on a bench. Put the consumer key and secret in the vault Postman's local vault, never synced The secret never sits in a request, a file or a chat. Client credentials a POST to your My Domain token address No person: the token runs as the app's integration user. Web server flow with PKCE Postman opens the browser; you sign in at Salesforce You type your password only into Salesforce. Call the REST API, then revoke the same call with each token Compare who each call ran as; then take both tokens back. 1 2 3 4 5 WHY No username-password flow anywhere: it retires on 20 February 2027. HOW TO READ IT 1 the order a step the step that matters most what comes next © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

The same rules on your bench as in production.

You’ll need a Developer Edition org of your own, Postman, and the Postman setup from chapter 2.

1. Create the External Client Apps. In Setup, enter external client in the Quick Find box, select External Client App Manager, and click New External Client App. Expand API (Enable OAuth Settings) and select Enable OAuth. Make two:

  • Bench — server. Enable the client credentials flow, choose an integration user for it to run as in the app’s policies (module 4), and give it the api scope.
  • Bench — person. For the callback URL, enter https://oauth.pstmn.io/v1/callback (or https://oauth.pstmn.io/v1/browser-callback if you use Postman in a browser), and give it the api and refresh_token scopes.

Salesforce warns that a new External Client App “can take up to 30 minutes to become available” (Create an External Client App (opens in a new tab), Salesforce Developers, checked 2026-11-07). Get a coffee.

2. Put the secrets in the vault. From each app, copy the consumer key, and for the server app, the consumer secret. In Postman, put them in your local vault: “Only you can access vault secrets in your Postman Local Vault, and they aren’t synced to the Postman Cloud” (Store secrets in Postman Vault (opens in a new tab), Postman Docs, checked 2026-11-07). From now on, your requests say {{vault:bench-server-secret}}, never the secret itself.

3. Client credentials: the food festival. On a new request, open Authorization, choose OAuth 2.0, and configure a new token: Grant Type Client Credentials; Access Token URL https://YourMyDomain.my.salesforce.com/services/oauth2/token; Client ID {{vault:bench-server-key}}; Client Secret {{vault:bench-server-secret}}. Use your My Domain address: 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” (OAuth 2.0 Client Credentials Flow for Server-to-Server Integration (opens in a new tab), Salesforce Help, checked 2026-11-07). Get the token.

4. The web server flow with PKCE: the burger house. On a second request, configure a new token: Grant Type Authorization Code (With PKCE); select Authorize using browser; Auth URL https://YourMyDomain.my.salesforce.com/services/oauth2/authorize; Access Token URL the same token address as step 3; Client ID {{vault:bench-person-key}}; Client Secret left blank; Code Challenge Method SHA-256; Code Verifier left blank, so Postman makes one; Scope api refresh_token. These settings follow Salesforce’s own Postman guide, adapted from its MCP servers to the REST API (Configure Postman (opens in a new tab), Salesforce Developers, checked 2026-11-07). Get the token: the browser opens Salesforce’s login page, you sign in there, and Postman receives the token. The pickup word from module 5 is the code verifier Postman made.

5. Call, compare, revoke. Look at each token response first. Alongside the access token, Salesforce returns an id, the identity URL, which names the user the token belongs to. Compare them: the first is the integration user you chose; the second is you. Same org, two identities, decided by the flow. Then send the same request with each token:

GET https://YourMyDomain.my.salesforce.com/services/data/v68.0/limits

and try a query on an object the integration user can’t see, to watch the permission set do its job. And when you’re done, revoke both tokens:

POST https://YourMyDomain.my.salesforce.com/services/oauth2/revoke
Content-Type: application/x-www-form-urlencoded
token={{the refresh or access token}}

Revoking is the habit. A bench left with live tokens is a bench someone else can use.

One more thing to notice. Postman doesn’t sync a token to its cloud unless you tell it to: “By default, Postman won’t sync your token in case you don’t want to share it” (Authenticate with OAuth 2.0 authentication in Postman (opens in a new tab), Postman Docs, checked 2026-11-07). Leave it that way.

Eight modules, one picture of a trusted integration:

  • It’s built knowing security keeps changing (module 1).
  • What crosses is protected past the channel, and some things never travel (module 2).
  • Its three doors are closed: no app anyone can approve, no token that does too much, no guest that sees too much (module 3).
  • It has its own identity, behind five gates (module 4).
  • It uses the right flow for its caller (module 5).
  • It’s built on an External Client App coming in and a named credential going out (module 6).
  • Its tokens rotate, expire when idle, can be taken back, and work only where they should (module 7).
  • And its secrets live only where they belong (module 8).

Test knowledge. Store outbound secrets in named and external credentials, never in code, records or custom fields an admin can read; keep a client’s secret in its own secret store. If a secret leaks: rotate, revoke the tokens it issued, then remove it. Client credentials token requests go to the My Domain URL, not login.salesforce.com or test.salesforce.com. A PKCE client can omit the client secret.

  • Where every secret lives, for every integration, in and out, with an owner and a rotation date.
  • The rule for records, code, tickets and AI tools: no secrets, written into the team’s standards, and checked.
  • The leak runbook: rotate, revoke, remove, review, and who does each.
  • The search that finds secrets already sitting in records, and how often it runs.
  • A bench for every developer that follows the same rules as production.