Resource indicators / audience binding (RFC 8707)
The shape
The agent specifies resource=https://shop.alpacanica.com at PAR time. The AS narrows
the issued JWT-AT's aud claim to exactly that resource. The SD-JWT VC mandate's aud claim matches.
Cross-resource use is refused: an AT issued for aud=shop.alpacanica.com MUST be rejected at shop.bristleandslate.com. Each aud is a distinct resource; agents request
a new AT per merchant.
AS metadata advertises resource_indicators_supported: true. AS metadata also enumerates
known resource URLs in resources_supported.
Three-layer audience binding
The merchant origin appears as the audience at three independent layers:
- JWT-AT
aud: the AS pins this on token issue. - Mandate VC
aud: same value, same merchant. - KB-JWT
aud: the agent commits to this at presentation time.
All three MUST match the merchant's exact origin (lowercase scheme + host, no default port, no path). The merchant verifier rejects any mismatch.
Worked example
# PAR request narrows the resource:
curl -sS https://as.oid4pay.com/oauth/par \
--data-urlencode "resource=https://shop.alpacanica.com" \
--data-urlencode "authorization_details={\"type\":\"oid4ac_mandate\", ...}" \
...
# Token response carries an AT with aud=https://shop.alpacanica.com:
{
"access_token": "<JWT-AT>",
"token_type": "DPoP",
"expires_in": 300,
"mandate_jwt": "<SD-JWT VC>"
}
# The merchant at https://shop.bristleandslate.com verifies and rejects:
// payload.aud === "https://shop.alpacanica.com"
// own resource === "https://shop.bristleandslate.com"
// -> rejected with aud_mismatchCross-resource policy
A mandate with a multi-merchant scope is permitted by carrying the aud claim as a JSON array. The JWT-AT, however, is always single-audience: the agent
requests a fresh AT per merchant audience. This preserves the property that AT leak across merchants
is impossible.
Proxied deployments
When a merchant proxies through a gateway server-to-server (for example api.mailodds.com), the aud may be the gateway origin instead of the merchant
origin. Both shapes work. When a merchant validates the token locally, the aud is that
merchant's own origin.