Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

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.

Deciding whether to trust an authorization server

A valid document proves only that the API said it. authorization_servers is the API's claim about where to get tokens, and RFC 9728 leaves the decision to trust a listed server with the client. Two abuses show why that decision matters.

A malicious API can list an authorization server its operator controls, with a sign-in page made to look like your photo service's. The printer would send you there to connect your library, and you might type your photo service password into it. A client that discovers authorization servers should show people the server's real domain before sending them there. The habits that resist phishing elsewhere matter here too, such as password managers that fill in a password only on the domain where it was saved, and authenticators that cannot be used on the wrong site.

A malicious API can also list a genuine authorization server and ask for a scope that another API uses. If that authorization server issued tokens every API would accept, the malicious API could replay the printer's token elsewhere. Requesting an audience-restricted token with the resource parameter, as the printer did in Locating its authorization servers, limits a token obtained for one API to that API.

Beyond those defenses, a client needs a policy. The printer might accept only authorization servers on a list its operators maintain, or only those where it already has a registration, and treat anything else as a reason to ask you or to stop. The same decision applies when an API the printer already uses starts naming a different authorization server. The specification lets an API change servers this way, and a client should judge the new server as carefully as a stranger. Whatever the policy, two rules hold: tokens issued for one API are never sent to another, and credentials registered at one authorization server are never presented to another.

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.

Try it in the Lab

PUT IT INTO PRACTICE

Check your understanding

Try these questions before moving on. If an answer isn't right, use the feedback and try again.

0 of 2 answered correctly

Enable JavaScript to answer these questions and save progress in this browser.

QUESTION 1 OF 2The printer calls https://api.attacker.example, whose challenge points at the photo API's genuine metadata. That document's resource is https://api.photos.example. What should happen?

QUESTION 2 OF 2Why should the printer's backend refuse to fetch discovered metadata addresses that resolve to internal network addresses?

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

Learn identity