Skip to content

On the Wire

Module 2 of 5 in the chapter The Burger House: Flows With a Person, chapter 9 of Securing Salesforce: Identity and Access. Each module stands on its own.

The question this module answers: What exactly is sent at each step of the web server flow?

Count the trips the Burger House makes to Salesforce. There are only two. One is a normal login screen, but with a couple of parameters on the address. The other is a call to the token endpoint with the code. That’s all. Really, it’s not that complicated.

Here’s each one, as Salesforce documents it (S1).

The Burger House sends Priya’s browser to Salesforce’s authorize endpoint, on your My Domain, with the details in the address:

https://MyDomainName.my.salesforce.com/services/oauth2/authorize?
client_id=*******************&
redirect_uri=https://burgerhouse.example.com/oauth2/callback&
response_type=code&
scope=api%20refresh_token&
state=7f3a9c
  • response_type=code asks for a code, not a token. That’s what makes it the web server flow.
  • client_id says which app is asking.
  • redirect_uri is where Salesforce sends her back. It “must match one of the values in the external client app’s Callback URL field. Otherwise, the approval fails” (S1).
  • scope is what the app asks for this time. Unlike client credentials in chapter 8, you can ask here, but only for what the app has: “The scopes passed in this parameter must be a subset of the registered scopes” (S1). Leave it out, and you get all the app’s scopes.
  • state is a value the app makes up; Salesforce passes it along (S1), so the app can check that the answer belongs to a request it sent.

There’s no secret in this address. It goes through the browser, and anything in the browser can be seen.

At Salesforce, Priya signs in, with MFA, and sees the approval page: the Burger House wants to reach your data, allow or deny. If she has approved it before, “it isn’t necessary to approve access again” (S1).

When she approves, Salesforce sends her browser back to the callback address, with the code on the end (S1):

https://burgerhouse.example.com/oauth2/callback?code=*******************&state=7f3a9c

Two details matter:

  • The code is short-lived. “The authorization code expires after 15 minutes” (S1). It’s a claim ticket, not a wristband.
  • The state comes back with it. The Burger House checks it’s the one it sent.

That’s the end of the front channel.

Now the Burger House, from its own server, swaps the code at the token endpoint (S1):

POST /services/oauth2/token HTTP/1.1
Host: MyDomainName.my.salesforce.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=*******************&
client_id=*******************&
client_secret=*******************&
redirect_uri=https://burgerhouse.example.com/oauth2/callback

Look at it next to chapter 8. Same address, same shape: a grant_type and something presented. This time what’s presented is the code, plus the app’s own ID and secret: the code proves Priya said yes, and the secret proves this is the Burger House. The redirect_uri has to match again.

Back on the back channel comes the same kind of answer you read in chapter 8 (S1):

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

Two differences from client credentials. The id names Priya, not an integration user: the wristband is hers. And there’s a refresh token, because the app asked for the refresh_token scope and this is a flow with a person (chapter 8, module 5). The Burger House stores it carefully, and won’t have to send Priya to the login screen every time.

Then step 5: the Burger House calls the API with Authorization: Bearer and the access token, just as in chapter 8, and gets back what Priya may see.

Most failures in this flow are one of three:

  • The callback doesn’t match. One letter, one slash, http instead of https: “the approval fails” (S1). Check the address in the request against the app’s Callback URL field, exactly.
  • The code has expired. It lasts fifteen minutes (S1).
  • The secret is wrong, or missing where the app requires it (S1).

When I demo this, I paste the authorize address into a private window by hand, sign in, and copy the code off the callback. It’s slow, but you see every piece, and once you’ve seen them, the error messages make sense.

In 2023 I made a video of these requests, by hand: the authorize address in a private window, the code off the callback, the token request, then the API call with the Bearer token. It doesn’t use PKCE yet, which module 3 adds. The note under the video says what’s still right and what’s changed since.

STA 3.13 · OAuth Web Server Flow: Details and Demo · 9:49 · published 2023-10-05 · plays from YouTube when you click it · Watch on YouTube · More videos: Salesforce Identity & Access Videos

Module 3: the moment the code sits in the browser, and the pickup word that closes it.

  • The callback URLs on each app, exact, and only the ones it needs.
  • Which scopes the app has, and which it asks for each time.
  • That the app checks state on the way back.
  • Where the refresh token is kept on the app’s server.