In an RFC 8693 token exchange, how do the `audience` and `resource` parameters narrow the issued token, and when does the server answer `invalid_target`?
answer
- say where the token may be used
- narrow it to one callee
- resource is a URI, audience a name
- server reflects the target into aud
- invalid_target when it will not issue
basics
~20 saudience and resource name the service the issued token should be good for, and the authorization server reflects that into the token's aud claim. When it cannot or will not issue for the named target, it answers invalid_target.
solid answer
~40 sBoth name the intended target of the issued token: `resource` as an absolute URI in the sense of `RFC 8707` resource indicators, `audience` as a logical name the server already knows the service by. Either may appear more than once, and the server reflects its decision into the issued token's `aud`, which is what lets a target reject a token minted for somebody else. `scope` is the separate axis — where the token may be used versus what it may do there. If the server is unwilling or unable to issue for the targets named, `RFC 8693` says it SHOULD return `invalid_target`, as an HTTP `400` error from the exchange itself — not a rejection by the downstream service, which has not seen anything yet.
code
http · 8 linesHTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
{
"error": "invalid_target",
"error_description": "unknown or not permitted target for this client"
}go deeper
Recall that audience and resource say where the issued token may be used, and that invalid_target is the authorization server refusing rather than the target service complaining.
Explain the split: the target parameters narrow where, scope narrows what, and the server reflects the target it accepted into the issued token's aud claim.
Diagnose it properly. invalid_target means a misconfigured or unpermitted target, so retrying unchanged is pointless, and a request honoured only in part shows up as a narrower granted scope.
Owning a fleet, the question is how targets are named and registered so that narrowing is possible at all, and who maintains that mapping as services are added and retired.
## Saying where the issued token may be used An exchange that names no target tends to hand back a token about as broad as the one it consumed, which defeats most of the point of exchanging. `RFC 8693` gives the caller two parameters for saying where the issued token is meant to be good: - **`resource`** — an absolute URI identifying the target service, in the sense of `RFC 8707` resource indicators. It is the target's location. - **`audience`** — a logical name the authorization server already knows the target by. It is the target's name. Both are OPTIONAL, both may appear more than once in a single request, and they may be combined. What the authorization server does with them is reflect its decision into the issued token, typically as the `aud` claim, so a service receiving the token can tell it was minted for itself and reject one that was not. | parameter | shape | answers | |---|---|---| | `resource` | an absolute URI | *where* the target is | | `audience` | a logical identifier | *what the target is called* | | `scope` | space-delimited strings | *what may be done there* | `scope` is an independent axis: the target parameters narrow **where**, `scope` narrows **what**. Either can be cut down by the server, and when the granted scope differs from the requested one the response carries a `scope` member saying what was actually granted. ## When the answer is `invalid_target` If the authorization server is unwilling or unable to issue a token for the target or targets indicated, `RFC 8693` says the `invalid_target` error code SHOULD be used. It arrives as an ordinary OAuth 2.0 error response — HTTP `400` with a JSON body carrying `error` and usually `error_description`. What it means in practice, in rough order of frequency: 1. The named target is not known to this authorization server at all — a typo in a URI, or a service that was never onboarded. 2. The target is known, but this client is not permitted to obtain tokens for it. 3. Several targets were named, and the server will not mint one token covering all of them. What it does **not** mean is that the downstream service rejected anything. Nothing has been presented to the target yet; this is the authorization server declining, at exchange time, before any token exists. Retrying the identical request produces the identical error, so the fix is configuration or a corrected target, never a retry loop. ## Requested is not issued The same "you asked, the server decided" pattern runs through the rest of the response, and handling it is the other half of the caller's job: - `requested_token_type` expresses the type the caller would like. The response's REQUIRED `issued_token_type` states what it actually got, and the two may differ. - The target may be narrowed to fewer services than were named — or the request refused outright with `invalid_target` rather than quietly satisfied in part. - The granted scope may be narrower than the requested scope, in which case the response says so. A caller that assumes its request was honoured verbatim will eventually present a token somewhere it is not good, and that failure surfaces at the target rather than at the exchange, which is considerably harder to trace back. ## A worked case A reminder service for a blood-donation programme exchanges a donor's access token for one it will present to a messaging provider. It names the messaging provider in `resource` and asks for a single scope. Three outcomes are normal, and the client has to distinguish them: 1. **A token whose `aud` is the messaging provider.** Use it for that one call. 2. **A token with a narrower `scope` than requested.** Usable, but the operation the service planned may still fail at the target; read the response's `scope` rather than assuming. 3. **`400` with `invalid_target`.** The exchange did not happen. Something about the named target is wrong or not permitted, and no amount of retrying changes it. Narrowing is the whole reason to spend a round trip on an exchange. The token that comes back should be good for one callee, for as little as that callee needs, so that losing it costs materially less than losing the token that went in — and that only happens if the caller names a target and then reads what it was actually given.
- Can `resource` and `audience` appear more than once in a single exchange request?Yes. A caller may name several targets, and the authorization server decides whether it is willing to mint one token good for all of them. If it is unwilling or unable to cover every target named, `RFC 8693` says it should answer `invalid_target` rather than quietly issuing a token for only some of them.
- How does `scope` interact with the target parameters?They are independent. The target parameters say where the issued token may be used; `scope` says what it may do there. Either may be cut down by the authorization server, and when the granted scope differs from the requested one, the response includes a `scope` member stating what was actually granted.
- What happens if the caller names no target at all?The authorization server applies its own default — often the audience of the subject token, or a configured default for that client. Nothing in the grant requires a target to be named, which is exactly how an exchange ends up producing a token as broad as the one it consumed, with none of the narrowing that justified the round trip.
saying these in an interview costs you the question
- Thinks audience and resource widen a token rather than narrow it.
- Reads invalid_target as the downstream service rejecting the token.
- Assumes omitting audience and resource still yields a target-specific token.
- Believes scope and the target parameters express the same restriction.
- Treats invalid_target as transient and retries the identical request.