skip to content

Why does RFC 6749 say a client credentials token response should not include a refresh token?

level: middleimportance: should knowfreq 50%

answer

  1. refresh exists because the owner has gone
  2. no owner means nothing to continue
  3. the client can just ask again
  4. an extra secret buying no extra reach
  5. SHOULD NOT, not MUST NOT

basics

~20 s

The refresh token grant exists to renew an access token while the resource owner is absent. The client credentials grant has no resource owner to be absent: the client can authenticate again at any moment, so a refresh token adds exposure and no capability.

solid answer

~40 s

A refresh token answers one problem: the access token has expired and **the resource owner is no longer there to approve another one**. The client presents `grant_type=refresh_token` at the token endpoint and gets a fresh access token with no user interaction. In the `client_credentials` grant that problem never arises, because the client's own credentials are the authorisation — it can repeat the same request whenever it needs a token. A refresh token would therefore be a second long-lived bearer credential granting nothing the client did not already have, and one more secret to store and leak. Note the strength: RFC 6749 says a refresh token **SHOULD NOT** be included, not MUST NOT, so servers that issue one are unusual rather than non-conformant.

code

http · 15 lines
http
POST /token HTTP/1.1
Host: as.catalogue.example
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "access_token": "2YotnFZFEjr1zCsicMWpAA",
  "token_type": "Bearer",
  "expires_in": 3600
}

go deeper

for a junior

Remember what a refresh token is for: getting a new access token once the person who approved the first one has gone away.

for a middle

Explain the asymmetry — the client credentials grant never had a resource owner, so nothing needs continuing, and the client can simply authenticate again.

for a senior

Point at the operational cost you have carried: a second long-lived secret in the same store, with its own rotation nobody scheduled, granting no reach the client lacked.

for a principal

Frame it as credential inventory: every additional long-lived secret is a rotation obligation and a compromise multiplier, so refuse the ones that buy no capability.

## What the refresh token grant is for `refresh_token` is a `grant_type` in its own right, used at the token endpoint after some earlier grant produced both an access token and a refresh token. The request is a plain back-channel POST carrying `grant_type=refresh_token` and the refresh token itself; the response is a token response like any other. No browser, no redirect, no resource owner. That last point is the whole purpose. The authorization code grant puts the buyer in front of the authorization server exactly once. Afterwards the buyer closes the tab and goes home, while the ordering integration still needs to place their order at 17:58. The refresh token is what lets the client carry on **in the owner's absence** without either keeping their password or dragging them back through a redirect. ## Why the client credentials grant does not need one | | Authorization code grant | Client credentials grant | |---|---|---| | Who authorised the token | A resource owner, once, in person | The client's own credentials | | Can that party be re-consulted cheaply? | No — they have gone | Yes — the client always has its credentials | | Value of a refresh token | Continue without the owner | None: it duplicates the client's own credentials | | RFC 6749's position | A refresh token MAY be issued | A refresh token SHOULD NOT be included | When the nightly stock-and-price sync's access token expires mid-run, the correct behaviour is not to refresh it — it is to make the same `client_credentials` request again. The credential that would authenticate the refresh request is the same credential that would authenticate a fresh grant request, so the refresh token buys nothing and costs: - **Another long-lived secret to store**, in the same place the client credentials already live, doubling what a compromise of that store yields. - **Another credential to rotate**, on its own schedule, usually forgotten. - **A misleading token inventory**, where a refresh token implies somebody delegated something when nobody did. ## Reading the strength of the rule correctly RFC 6749 words this as **SHOULD NOT**, and an interview answer that promotes it to MUST NOT is teaching a false certainty. A conformant authorization server may issue one; some do, usually because a single code path serves every grant. The right response to finding one in a token response is to stop using it and to ask the server's operator why it is there, not to declare the server broken. ## What this reveals about the taxonomy The rule is a good probe because it can only be answered from the *meaning* of each grant rather than its parameter list. A candidate who has memorised the grants recites that `client_credentials` takes no `redirect_uri`; a candidate who understands them can say why absence of the resource owner is the axis that decides everything here: 1. `authorization_code` — an owner is present and delegating. 2. `refresh_token` — the same delegation, continued after the owner has gone. 3. `client_credentials` — no owner was ever involved, so there is nothing to continue. A related trap: the refresh token is a credential **for the token endpoint only**. It is presented to the authorization server, never to a resource server, and a client that sends one in place of an access token on an API call has confused the two. Equally, the fact that a refresh request needs no human does not make it unattended in the client credentials sense — it still rests on a grant a human once gave. ## What to say in an interview Name the purpose (continue without the owner), state the asymmetry (the client credentials grant has no owner to be absent), give the operational consequence (an extra long-lived secret for no extra capability), and quote the strength accurately as a SHOULD NOT. Then say what the job actually does when its token expires: request another one, with the same credentials, as often as it likes.

  • Which grant can hand a client a refresh token in the first place?
    The authorization code grant may include one in its token response, which is what lets the client keep acting after the buyer has left. The retired password grant could too. The client credentials grant should not, because there is no absent owner whose delegation needs continuing.
  • The nightly job's access token expires halfway through its run. What should it do?
    Repeat the `grant_type=client_credentials` request with its own credentials and continue with the new access token. No human is involved and none is needed, which is exactly why a refresh token would add nothing.
  • Where may a refresh token be presented?
    Only at the authorization server's token endpoint. It is not an API credential: a resource server has no way to act on one, and a client sending it in place of an access token has confused a credential for obtaining access with a credential for using it.

saying these in an interview costs you the question

  • Says a machine job needs a refresh token to keep running
  • Reads the SHOULD NOT as a MUST NOT the server must enforce
  • Thinks refreshing requires the resource owner to be present
  • Sends a refresh token to the resource server as a credential
  • Assumes the client credentials grant has an absent owner behind it