intermediate 3 min answer Multiple choice

A developer platform ships a CLI that must act as the signed-in user on machines that may have no browser at all - SSH sessions on servers and containers in continuous integration. Which OAuth flow should the CLI use?

oauthdevice grantpkcecliworkload identity
Pick one
Show the full answer Hide the answer

The deciding property

Whether a browser can be opened on the machine where the command runs. Every other consideration - token storage, refresh, scopes - is common to all four options. Only one of them works when the answer is no.

The device authorisation grant, specified in RFC 8628 (2019), exists for exactly this: the CLI asks the authorisation server for a short user code, prints it with a URL, and polls while the user completes the sign-in on a device that does have a browser. Nothing secret ever passes through the constrained machine.

Why not the others, and when each would be right

  • Authorization code with PKCE on a loopback redirect is the correct answer for a native or desktop application on a machine with a browser, and it is better than the device grant there - fewer steps, no code to copy. It is also what the CLI should use when it detects a usable browser. It simply cannot complete on a headless host, which is the constraint in the stem. Ship both and choose at runtime.
  • Client credentials with a secret in the binary fails twice. A secret shipped to users is not a secret - it is extractable from any installation - and client credentials authenticate the client, not the user, so every action would be attributed to the CLI rather than to a person. That destroys the audit trail, which for a developer platform is the thing auditors ask about.
  • Resource owner password credentials means the CLI collects the user's password, which defeats federated sign-in, cannot carry multi-factor authentication, and trains users to type their password into tools. The grant was deprecated in the OAuth 2.0 security best-current-practice work and should not be used in new designs.

What would flip the decision

If this changes Choose Because
The CLI is running in CI, not under a person OIDC workload federation - no user flow at all A pipeline is not a user; an exchanged workload token is short-lived and attributable to the job, with no stored credential
A browser is reliably available Authorization code with PKCE on loopback Fewer steps and no copying; the device grant's user code is a phishing-shaped interaction
The CLI needs to act for an organisation rather than a person An installed application identity with scoped permissions User tokens inherit everything that user can reach, which is far more than the task needs

What it costs

The device grant's weakness is social: users are trained to type a code shown by one program into a page opened by another, which is the shape of a real phishing technique. Mitigate it by displaying the requesting client's name and the scopes on the confirmation page, keeping the code's lifetime short - typically 5 to 15 minutes - and rate-limiting the polling endpoint.

Common weak answers

  • "Use client credentials; it is our own tool." Authenticates the tool, not the person, so every action is attributed to the CLI and the audit trail is gone.
  • "Prompt for the password; we are first party." Defeats federated sign-in, cannot carry multi-factor authentication, and trains users to type passwords into tools.
  • "Mint a long-lived personal access token and paste it in." Works, and replaces a managed grant with an invisible permanent credential in a shell history and a dotfile.

What it costs, continued

The deeper cost is the token the CLI then holds. A user token carries that user's whole reach. Store it in the platform keychain rather than a dotfile, scope it to what the CLI needs, give it an expiry with a refresh token, and make revocation visible to the user in account settings. For CI, the right answer is the first row of the table: do not let a pipeline hold a human's token at all.