Trust and metadata validation
Discovery hands some of a client's decisions to documents written by other people. The API's document chooses the authorization server the printer sends you to. The authorization server's document chooses where your code and the printer's credentials go. For the photo service, those documents say what the printer's developers would have configured anyway. For an API someone typed into a box, they say whatever its operator wants them to say.
Checking the resource value
The first check mirrors the issuer check from Validating metadata and issuer identity. A metadata address is built from a resource identifier, as https://api.photos.example/.well-known/oauth-protected-resource is built from https://api.photos.example, and the document's resource member must be identical to the identifier its address was built from. If it is not, the client must not use any of the document.
A second check applies when the metadata address came from a challenge, and it stops a quieter trick. All domains and tokens in these examples are fictional. Suppose you were persuaded to add a library at https://api.attacker.example. The printer calls that address, and the attacker's API answers with a challenge that points at the photo API's genuine metadata:
GET / HTTP/1.1
Host: api.attacker.example
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://api.photos.example/.well-known/oauth-protected-resource"
Everything the printer fetches next is authentic, and it passes the first check. The document is the photo API's own, it names the real photo service, and you sign in at the real photo service. The printer receives a genuine token for the photo API, so audience restriction does nothing to stop what follows. The printer then sends its requests for your photos to the attacker's API, the address you gave it, with that token attached, and the attacker replays the token at the real photo API.
The defense is to compare the document's resource with the address the client actually called. When metadata was found through a challenge, RFC 9728 requires its resource value to be identical to the URL the client used for the request that produced the challenge, and if it is not, none of the document may be used. The comparison is exact, like the issuer comparison, so it matches only when the client called the resource identifier itself. In code, that means comparing with the address as the client stored it, not a copy an HTTP library has rewritten, for example by adding a trailing slash. The printer's discovery request to the photo API went to https://api.photos.example, the address you typed and exactly the identifier the photo API's document names, so the genuine API passes. Here the printer called https://api.attacker.example while the document names https://api.photos.example, so the printer stops before any token exists.
Fetching and refreshing safely
Discovery makes the printer's backend request addresses that other parties chose: the API address you typed, the metadata address in a challenge, the issuer in a document. That invites server-side request forgery, tricking a server into sending requests to addresses an attacker picks, often internal services the attacker cannot reach directly but the server can. Someone who entered an internal address as their photo library could make the printer's backend probe the printing company's own network.
RFC 9728 says clients should take precautions against this, such as blocking requests to internal address ranges. In practice, a backend that fetches discovered addresses accepts only HTTPS, resolves each host and rejects private, loopback, and link-local addresses, applies the same rule to any redirect, and limits how long it waits and how much it reads. It checks the server certificate on every fetch, exactly as it does for authorization server metadata.
Resource metadata is fetched with an ordinary HTTP GET, so ordinary caching applies, and an API can say how long its document may be reused with a Cache-Control header. When an API sends a new challenge containing resource_metadata, the client fetches the document again and validates the fresh copy as it did the first. Like authorization server metadata, a resource's document can also carry signed_metadata; a client that supports it checks the signature and decides whether it trusts the signer.
None of these checks makes an unknown API trustworthy. They make sure the printer acts only on documents that really describe the API it called and the authorization server it chose, and only after deciding that server deserves your visit. With the photo service, the printer already had a client ID, photo-printer. At an authorization server it has only just discovered, it has none, and no authorization flow can start there until it does. That is where Dynamic client registration begins.