Skip to content

Checkpoint challenge

Original, hands-on practice. Never modeled on actual exam questions. This closes the chapter The Burger House: Flows With a Person, chapter 9 of Securing Salesforce: Identity and Access.

A small command-line tool needs to read Accounts as the person running it. It has no web page of its own and nowhere to type a password safely. That’s what the device flow is for: Salesforce says command-line apps can use it too (S7).

Your terminal plays the device. Your browser plays Priya’s phone.

  • A local external client app with a localhost callback URL and the device flow enabled.
  • The device’s two requests from a terminal: one for the codes, then polling for the tokens.
  • The user code typed on another screen, as a normal user, and the device approved.
  • An API call with the token the device gets, as that user.
  • A Developer Edition org, with a normal user to sign in as; not the admin.
  • The app’s client ID only. The device never gets the secret (S7).
  • Ten minutes: the codes expire, so have both windows ready before step 4.

1. Have a user ready. A normal test user in the org who can read Accounts, the kind you used in chapter 4. You’ll sign in as this user in step 4.

2. Make the app. In External Client App Manager, create a local external client app, “Command-line tool”. In its OAuth settings, enable OAuth, set the callback URL to a localhost address, such as http://localhost:1717/OauthRedirect, choose the scopes api and refresh_token, and enable the device flow (S7). Save, then copy its consumer key. If the device flow setting’s name looks a little different on your page, look for “device flow” in the OAuth settings.

3. Ask for codes. In a terminal, as the device (S7):

Terminal window
curl -s -X POST https://YOUR-DOMAIN.my.salesforce.com/services/oauth2/token -d response_type=device_code -d client_id=YOUR_KEY

Read the answer. You should see a device_code, a user_code of 8 letters and numbers, a verification_uri, and an interval. Copy the device code somewhere private. The clock is running: both codes last 10 minutes (S7).

4. Be Priya on another screen. Open a private browser window, go to the verification_uri, and sign in as your test user. Type the user code, and approve the app.

5. Poll, as the device. Back in the terminal, ask for the tokens with the device code (S7):

Terminal window
curl -s -X POST https://YOUR-DOMAIN.my.salesforce.com/services/oauth2/token -d grant_type=device -d client_id=YOUR_KEY -d code=YOUR_DEVICE_CODE

If you run it before approving in step 4, you’ll get an answer that says not yet; wait at least the interval and try again. Salesforce’s error for this is authorization_pending: “the user hasn’t approved the device for access yet” (S11). Once approved, you get an access_token and a refresh_token (S7).

6. Call the API, as her. Use the access token on a query (the API version from https://YOUR-DOMAIN.my.salesforce.com/services/data):

Terminal window
curl -s "https://YOUR-DOMAIN.my.salesforce.com/services/data/v66.0/query?q=SELECT+Name+FROM+Account+LIMIT+3" -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Then look at the id in the token answer: whose user ID is it?

7. Take it back. Revoke the refresh token, as in chapter 8 (S4 there):

Terminal window
curl -s -X POST https://YOUR-DOMAIN.my.salesforce.com/services/oauth2/revoke -d token=YOUR_REFRESH_TOKEN

Run the query again. Revoking a refresh token revokes its access tokens too.

Why did the device send only its client ID? Because a device, like a phone app, can’t keep a secret. The proof that it’s allowed comes from the person approving it on another screen, not from a secret on the device.

What stopped another device from grabbing your tokens with the user code? The device code. The person types the user code; the tokens go only to whoever presents the device code, and that never left your terminal.

Why did the device get a refresh token, when client credentials in chapter 8 didn’t? Because there’s a person in this flow. The device acts for her, and the refresh token lets it keep going without asking her to type a code again.

What would break on November 30, 2026, if this were a connected app? The device flow is now only for local external client apps with a localhost callback URL; non-compliant apps are blocked (S7, S8).

Read the wire: the web server flow. No org needed for this one. Here are the Burger House’s three requests from module 2, with PKCE and OpenID Connect. For each, say which channel it travels on, what’s in it that a thief could see, and why that doesn’t help them:

1. https://MyDomainName.my.salesforce.com/services/oauth2/authorize?response_type=code
&client_id=…&redirect_uri=https://burgerhouse.example.com/oauth2/callback
&scope=openid%20api&state=7f3a9c&code_challenge=…
2. https://burgerhouse.example.com/oauth2/callback?code=…&state=7f3a9c
3. POST /services/oauth2/token
grant_type=authorization_code&code=…&client_id=…&client_secret=…
&redirect_uri=https://burgerhouse.example.com/oauth2/callback&code_verifier=…

The first two go through the browser. A thief could see the code_challenge and the code: the fingerprint can’t be run backwards, and the code is useless without the secret and the pickup word. The third goes server to server, with the secret and the pickup word, the code_verifier, and its answer carries the access token, the refresh token and, because of openid, the ID token (modules 2 to 4).

  • The app: local, with a localhost callback, the device flow on, api and refresh_token.
  • The codes: a user code you typed on another screen, a device code that stayed in the terminal.
  • The tokens: an access token and a refresh token, for your test user, not the admin.
  • The revoke: the query refused afterwards.
  • IDP-1 (choosing the OAuth flow): the device flow, and why the web server flow is different.
  • IDP-3 (OAuth implementation concepts): codes, tokens, refresh and revocation.