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?
Two trips to Salesforce
Section titled “Two trips to Salesforce”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).
1. The authorize request
Section titled “1. The authorize request”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=7f3a9cresponse_type=codeasks for a code, not a token. That’s what makes it the web server flow.client_idsays which app is asking.redirect_uriis 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).scopeis 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.stateis 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).
2. The callback
Section titled “2. The callback”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=7f3a9cTwo details matter:
- The code is short-lived. “The authorization code expires after 15 minutes” (S1). It’s a claim ticket, not a wristband.
- The
statecomes back with it. The Burger House checks it’s the one it sent.
That’s the end of the front channel.
3. The token request
Section titled “3. The token request”Now the Burger House, from its own server, swaps the code at the token endpoint (S1):
POST /services/oauth2/token HTTP/1.1Host: MyDomainName.my.salesforce.comContent-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=*******************&client_id=*******************&client_secret=*******************&redirect_uri=https://burgerhouse.example.com/oauth2/callbackLook 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.
The answer
Section titled “The answer”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.
When it goes wrong
Section titled “When it goes wrong”Most failures in this flow are one of three:
- The callback doesn’t match. One letter, one slash,
httpinstead ofhttps: “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.
Watch it on video
Section titled “Watch it on video”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.
What’s next
Section titled “What’s next”Module 3: the moment the code sits in the browser, and the pickup word that closes it.
What an architect decides here
Section titled “What an architect decides here”- 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
stateon the way back. - Where the refresh token is kept on the app’s server.
Explore
Section titled “Explore”- OAuth 2.0 Web Server Flow for Web App Integration (opens in a new tab) (Salesforce Help, Winter ‘27; checked 2026-11-07)
