skip to content

In OAuth 2.0, what does an RFC 8693 token-exchange request send to the token endpoint, and what comes back?

level: juniorimportance: should knowfreq 30%

answer

  1. one token in, a different one out
  2. a grant type, not a new endpoint
  3. back channel, no browser, no redirect
  4. subject token plus its type URI
  5. response must state issued_token_type

basics

~20 s

An RFC 8693 token exchange is a back-channel POST to the token endpoint with grant_type set to urn:ietf:params:oauth:grant-type:token-exchange, a subject_token and its subject_token_type. The response returns a new token in access_token plus a required issued_token_type.

solid answer

~30 s

It is one more `grant_type` at the ordinary token endpoint, not a new endpoint: a form POST carrying `grant_type=urn:ietf:params:oauth:grant-type:token-exchange`, the token being handed in as `subject_token`, and a REQUIRED `subject_token_type` URI saying what that token is. Optional parameters narrow the result — `requested_token_type`, `audience` or `resource` for the target, and `scope`. The JSON response returns the minted token in `access_token` whatever its type, a REQUIRED `issued_token_type` saying what was actually minted, `token_type`, and usually `expires_in`. There is no browser, no redirect and no resource owner present, and the token handed in is not consumed by the exchange.

code

http · 10 lines
http
POST /token HTTP/1.1
Host: authorization-server.example
Authorization: Basic cmVtaW5kZXItc2VydmljZTpzM2NyZXQ=
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&subject_token=accVkjcJyb4BWCxGsndESCJQbdFMogUC
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token
&resource=https%3A%2F%2Fmessaging.example%2Fsend
&scope=reminders%3Asend

go deeper

for a junior

Remember the shape: a POST to the token endpoint with a special grant_type, one token in and a different token out. Recall that subject_token never travels without subject_token_type.

for a middle

Explain why this is a grant type rather than a new endpoint, name the registered token-type URIs, and say why issued_token_type is required in every response.

for a senior

Show that the input token survives the exchange, so the issued token must be narrowed deliberately by target and scope rather than inheriting the breadth of what it came from.

for a principal

The estate-level question is which clients are permitted to perform an exchange at all, who registers the targets they may name, and what a per-hop exchange costs in latency and authorization-server load.

## One more grant type, not a new endpoint OAuth 2.0 (`RFC 6749`) describes several ways for a client to *obtain* a token from a resource owner's authorisation. It says nothing about what a party that **already holds** a token does when it needs a different one — aimed at a different service, carrying fewer permissions, or in a different format. `RFC 8693` fills that gap with one additional `grant_type` value at the ordinary token endpoint: `urn:ietf:params:oauth:grant-type:token-exchange`. Everything else about the plumbing is unchanged. It is a back-channel form POST, it uses whatever client authentication the authorization server already requires of that client, and it answers with a JSON body. No browser is involved, there is no redirect, and no resource owner is present: the exchange is a conversation between a service and the authorization server about a token the service is already holding. ## What the request carries | parameter | status | what it carries | |---|---|---| | `grant_type` | REQUIRED | the URI `urn:ietf:params:oauth:grant-type:token-exchange` | | `subject_token` | REQUIRED | the token representing the party the new token is to be about | | `subject_token_type` | REQUIRED | a URI saying what `subject_token` is | | `actor_token` | OPTIONAL | a token representing the party that will act for the subject | | `actor_token_type` | REQUIRED with `actor_token` | a URI saying what `actor_token` is | | `requested_token_type` | OPTIONAL | the type the caller would like back | | `audience`, `resource` | OPTIONAL | the target service the issued token should be good for | | `scope` | OPTIONAL | the permissions asked for in the issued token | The type URIs are registered values rather than free text. The ones the specification registers are: - `urn:ietf:params:oauth:token-type:access_token` - `urn:ietf:params:oauth:token-type:refresh_token` - `urn:ietf:params:oauth:token-type:id_token` - `urn:ietf:params:oauth:token-type:jwt` - `urn:ietf:params:oauth:token-type:saml2` Two of those pull in different directions, and the distinction is worth holding: `...:access_token` names a **role** — an OAuth 2.0 access token, in whatever format the server likes, including an opaque string — while `...:jwt` names a **format** and says nothing about what the token is for. ## What the response carries - **`access_token`** — REQUIRED. The issued token, whatever its type. The member is named after the commonest case rather than after what it happens to hold, so an issued id_token or SAML 2.0 assertion arrives here too. - **`issued_token_type`** — REQUIRED. The URI saying what was actually minted. - **`token_type`** — REQUIRED. How the issued token is to be presented when it is an access token, for example `Bearer`. - **`expires_in`** — RECOMMENDED. Lifetime in seconds. - **`scope`** — present when what was granted differs from what was asked for. - **`refresh_token`** — OPTIONAL. `issued_token_type` is required precisely because `requested_token_type` is a preference and not an instruction: the server may return something else, and without the response saying so the caller would not know what it is holding. ## Why it is a grant type at all Making it a `grant_type` rather than a bespoke endpoint is what keeps it ordinary. The token endpoint already authenticates clients, already has error semantics from `RFC 6749`, and already returns tokens in a known shape. An authorization server advertises support by listing the exchange URI among `grant_types_supported` in its metadata, so a client that finds it absent knows the server will not do this at all, without having to try. ## What the grant does not do 1. It does not consume the input. The `subject_token` is not revoked or shortened by being exchanged; it remains valid on its own terms, which is why the issued token should be narrowed rather than left as broad as its input. 2. It does not turn the caller into the resource owner. No new consent is collected; the exchange rides on authorisation that already existed. 3. It does not change how the issued token is later validated. A resource server that receives one checks it exactly as it checks any other token from that issuer. A worked case: a reminder service for a blood-donation programme holds an access token for a donor and needs to call a messaging provider. It POSTs the donor's token as `subject_token` with `subject_token_type` set to `urn:ietf:params:oauth:token-type:access_token`, names the messaging provider as the target, and receives a fresh, narrower token back — a separate credential, minted for one hop, whose type the response states explicitly.

  • Why does the response return the issued token in a member called `access_token` even when the issued type is not an access token?
    Because the response reuses the `RFC 6749` token-response shape rather than inventing a member per type. `access_token` is the transport slot; `issued_token_type` is what tells the caller whether it holds an access token, a JWT, an id_token or a SAML 2.0 assertion. Read the type first and the member second.
  • What is the difference between requesting `urn:ietf:params:oauth:token-type:access_token` and `urn:ietf:params:oauth:token-type:jwt`?
    The first names a role: an OAuth 2.0 access token, in whatever format the authorization server prefers, including an opaque one. The second names a format — a JWT — and leaves its purpose open. A caller that needs to read claims locally asks for the format; one that simply needs to call an API asks for the role.
  • Does the exchange consume or invalidate the `subject_token`?
    No. Nothing in the grant revokes or shortens the token handed in; it stays valid until it expires or is revoked by other means. The exchange mints an additional credential, which is why the issued one should be narrowed by target and scope rather than left as broad as its input.

saying these in an interview costs you the question

  • Thinks the exchange happens at the authorization endpoint with a browser redirect.
  • Sends a subject_token without the required subject_token_type URI.
  • Assumes the issued token always matches requested_token_type.
  • Believes the exchange invalidates the token that was handed in.
  • Expects the issued token under a response member named after its own type.