---
title: "OAuth Discovery Metadata on 806 Sites: 133 Pass, and 47 of 50 Soft 200s Fail E1"
slug: oauth-discovery-metadata-adoption-corpus
published: 2026-11-04T03:09:47.015292+00:00
updated: 2026-11-04T03:09:47.015292+00:00
author: "M Asif Rahman"
author_url: https://ar.bd
category: "AI Readiness"
tags: check:P4, OAuth, RFC 9728, RFC 8414, MCP, agent discovery, corpus study, AI readiness
description: "133 of 806 sites pass the OAuth discovery check. 50 answer HTTP 200 without passing, and 47 of them also fail the soft-404 check. Own scan data, 4 Nov 2026."
url: https://aiscan.site/blog/oauth-discovery-metadata-adoption-corpus
---

Of 806 hosts in our scan corpus, 133 pass check P4, the OAuth discovery check. That is 16.5%. The more useful number is 50. fifty hosts answered HTTP 200 at an OAuth metadata path and still did not pass, and 47 of those 50 also fail our soft-404 check. A 200 at a well-known path is not evidence that the file exists.

## Quick summary

| Question | Answer | Source |
|---|---|---|
| How many hosts pass P4? | 133 of 806 (16.5%) | AIScan scan database, rubric 2026.08.2, 4 Nov 2026 |
| Who is scored on it? | 279 hosts detected as apps; the other 527 get "info" unless they publish | same |
| App hosts that pass | 50 of 279 (17.9%) | same |
| Hosts answering 200 but not passing | 50 (14 apps that fail, 36 non-apps shown as info) | same |
| Of those 50, how many also fail E1 (soft 404)? | 47 (94%) | same |
| Of the 133 passes, how many fail E1? | 11 (8.3%) | same |
| What the stored evidence cannot show | the JSON body of any metadata file | scan evidence stores status codes only |

**Short answer for a site owner:** if you run an authenticated API, publish the RFC 9728 document and confirm it returns JSON, not your HTML shell. Run `npx aiscan-cli yoursite.com` (or paste the address at [aiscan.site](https://aiscan.site/), free, no account) and read the P4 line and the E1 line together. If you would rather check by hand, the two `curl` commands are near the end.

## What P4 grades, and who it grades

P4 is the OAuth discovery check in the capabilities group. It requests two paths on the host: `/.well-known/oauth-authorization-server`, defined by [RFC 8414](https://www.rfc-editor.org/rfc/rfc8414) (June 2018), and `/.well-known/oauth-protected-resource`, defined by [RFC 9728](https://www.rfc-editor.org/rfc/rfc9728) (April 2025). The evidence string is always the two statuses, for example `auth-server: 404, protected-resource: 404`. The check page is on the [capabilities checks docs](https://aiscan.site/docs/checks/capabilities), and [OAuth Discovery for AI Agents](https://aiscan.site/blog/oauth-discovery-for-agents) explains what each file contains and how to publish it.

The check is marked optional and "bonus tier", weight 4. Scoring depends on what the scanner thinks the site is. Every scan stores a platform object with an `isApp` flag. On the 2026.08.2 rubric:

- If the site is an app and the files are missing, P4 is a **fail**.
- If the site is not an app and the files are missing, P4 is **info**, which carries no penalty.
- If the files answer properly, P4 is a **pass** for both.

This matters for reading every number below. A host that fails P4 and a host that shows info for P4 can have identical evidence strings. The difference is the `isApp` flag, which is a scanner judgement, not something the site declared.

## How we counted

We took the latest site-scope scan for each host on rubric 2026.08.2, excluded aiscan.site, and read check P4 and its evidence string from each stored report. That gave 806 hosts on 4 Nov 2026. Every figure here is an aggregate. No scanned host is named, and we did not fetch any third-party metadata file to fill gaps. The stored evidence holds status codes and nothing else, so what the files contain is out of view.

One caution on comparing with earlier posts. [Agent Discovery Files Census](https://aiscan.site/blog/well-known-agent-files-corpus) (31 Oct) reported 213 P4 passes in a larger population. This post uses one scan per host and a smaller, deduplicated corpus, and we have not reconciled the two sets of totals. Treat the numbers here as a snapshot of today's corpus and read the earlier post for its question about identical evidence with different statuses. The cut that answers that question is below.

## The full distribution

| Outcome | Hosts | Share of 806 |
|---|---|---|
| Pass | 133 | 16.5% |
| Fail | 233 | 28.9% |
| Info | 440 | 54.6% |

The fail group breaks down as 203 apps with 404 on both paths, 14 apps that answered 200 and still failed, 12 apps whose paths returned a block or server error (403, 429, 5xx and similar), 3 non-apps with 404 on both paths, and 1 non-app that returned a block or error. Those four non-app fails contradict the rule above, and the stored data does not say why; they are 0.5% of the corpus and we leave them as unexplained. The info group is 304 non-apps with 404 on both paths, 36 non-apps that answered 200, 92 non-apps whose probes were blocked or errored, and 8 where the paths could not be tested.

The 92 blocked or errored non-apps are worth a pause. Their mean score is 24.2, against 59.6 for the non-apps that answered 404 cleanly. A host that rate-limits or blocks the scanner fails the other checks too, so P4 is not what is dragging those scores down, but the evidence shows no usable reading either way.

## Three outcomes: absent, present and valid, present and invalid

The queue framing for this study was absent, present and valid, present and invalid. The stored data sorts hosts into the first cleanly. It cannot tell the other two apart directly, so we sort by status code and then look at what travels with the split.

| State | How we identify it | Hosts |
|---|---|---|
| Absent | 404 on both paths | 510 (203 app fails, 304 non-app info, 3 non-app fails) |
| Blocked or erroring | 403, 429, 5xx, 202 and similar | 105 |
| Answers 200 on at least one path, verdict pass | status 200 on either path | 133 |
| Answers 200 on at least one path, verdict not pass | status 200 on either path | 50 |
| Not tested | `n/a` on both paths | 8 |

The five rows add to 806. The fourth and third rows are the interesting pair: the same status code, two verdicts. Among the 133 passes, 105 answer 200 on both paths, 13 answer 404 then 200 (the resource file only), 12 answer 200 then 404 (the authorization-server file only) and three have one other status beside a 200. So the check accepts either document alone, which matches what we found on 31 Oct.

What separates the 133 from the 50? The scanner does not store the body, so we cannot say directly. What we can say is what travels with the split, and that is the next section.

## The 200s that do not pass are soft-404 hosts

For every host we also read E1, the check that tests whether a made-up URL returns a real 404. A host that answers 200 for a page that cannot exist fails E1. Here is E1 across the P4 groups:

| P4 group | Hosts | Also fail E1 | Share |
|---|---|---|---|
| App, answers 200, passes P4 | 50 | 2 | 4.0% |
| App, answers 200, fails P4 | 14 | 13 | 92.9% |
| Non-app, answers 200, passes P4 | 83 | 9 | 10.8% |
| Non-app, answers 200, info | 36 | 34 | 94.4% |
| App, no 200 on either path | 215 | 8 | 3.7% |
| Non-app, info, no 200 on either path | 404 | 20 | 5.0% |

Read the middle rows. Among hosts that answer 200 and are not given credit, 47 of 50 fail E1. Among hosts that answer 200 and are given credit, 11 of 133 do. The 200 that does not count is, in almost every case, a host that returns 200 for everything.

That is the same trap documented for Web Bot Auth key directories in [Web Bot Auth Key Directories: 78 of 797 Sites Answer 200, and Most Are Soft 404s](https://aiscan.site/blog/web-bot-auth-directory-adoption). In that study, 53 of 78 hosts answering 200 failed E1. P4 behaves differently from B3 in one respect worth stating: B3's pass and partial evidence strings were identical and indistinguishable, which was a scanner defect. P4's verdict does separate the soft-404 hosts from the others, on evidence we cannot see. So the verdict is better than the stored evidence suggests, which is the reverse of the B3 problem.

There is still a small residue of 11 passes that fail E1. Without the body, we cannot say whether those hosts serve a real metadata file and a catch-all page elsewhere, or whether the check was fooled. We have not fetched them and will not name them.

## The 14 apps that answer 200 and fail

These are the hosts the queue called "200 but fail". There are 14 today (13 with 200 on both paths, one with 200 on the auth-server path and 404 on the other), against 12 on 2 Nov. They share more than the status code:

| Trait | Hosts of 14 |
|---|---|
| Also fail E1 (soft 404) | 13 |
| Pass P1 (API catalog) | 13 |
| Pass or partial P2 (MCP server card) | 12 |
| Mean overall score | 53.8 |

A host that answers 200 to the three discovery probes, the catalog, the card and the OAuth paths, and also answers 200 to a URL that cannot exist, looks like a single-page app that serves its shell for every route. Each probe sees a 200 and a document. The scanner then has to decide whether that document is the thing it asked for. For P4 it evidently decides no, because these hosts fail. For P1 and P2 the stored verdicts read as credit on 13 and 12 of the same 14 hosts. We have no body to check that against, so we do not call those verdicts wrong. We say what to do about it: treat an agreement among well-known checks on a catch-all host as one finding, not three.

## A catch-all host passes more of everything

Hosts that answer 200 on everything look good on other discovery checks too. P1, the API catalog check, passes on 47 of the 50 hosts that answer 200 at P4 without credit (94%). Across the 623 hosts with no 200 at either P4 path, P1 passes on 50 (8.0%). We did not inspect P1's evidence for these hosts, so this is an observation about co-occurrence, not a finding that P1 is wrong. It is consistent with a host that returns 200 for any path. If you see a cluster of well-known files all "found" on one site, run E1 before celebrating.

## Why a status code is a weak signal on its own

An agent that reads `/.well-known/oauth-protected-resource` does not care about the status line. It parses JSON and looks for `authorization_servers`. The [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) states that the document returned by the MCP server "MUST include the authorization_servers field containing at least one authorization server". A shell page with a 200 fails that sentence in the first byte.

So the status code is an eligibility test, not a pass. A scanner that stops at the status code would credit all 50 of the hosts above. The corpus suggests ours does not, and that distinction has a price: it is invisible to the site owner. The evidence line reads `auth-server: 200, protected-resource: 200` whether the verdict is pass, fail or info. Of 153 hosts with that exact string today (105 pass, 13 fail, 35 info), 31% did not pass. Anyone reading only the evidence string would think they were in the first group. This is the same point we made about [evidence strings in general](https://aiscan.site/blog/evidence-string-audit): the string restates the probe, and the verdict carries information the string does not.

## Platform split

P4 is only scored as a fail on hosts the scanner detects as apps. In our corpus the platforms with 15 or more hosts split like this:

| Platform | Hosts | Detected as apps | P4 pass | Answer 200 on either path |
|---|---|---|---|---|
| Unknown | 297 | 0 | 15 | 44 |
| WordPress | 201 | 0 | 56 | 63 |
| Next.js | 200 | 200 | 27 | 33 |
| Astro | 44 | 44 | 13 | 13 |
| Shopify | 16 | 0 | 12 | 12 |

Every Next.js and Astro host is classed as an app. No WordPress, Shopify or unknown-platform host is. That is why the fail group is made of Next.js and Astro sites: 27 of 200 Next.js hosts pass (13.5%) and 13 of 44 Astro hosts pass (29.5%). It does not mean Next.js sites are worse at OAuth. A Next.js marketing site with no sign-in is scored as an app because the framework is. The same site on WordPress would show info.

The 56 WordPress passes (27.9% of 201) and the 12 Shopify passes (of 16) are the surprise. These platforms are not known for publishing OAuth metadata, and we cannot see the files. The shared platform is a hint that something in the stack, or in a common plugin or app, serves these paths. We did not test that, so it stays a hint.

## What the scores say, and what they do not

| Group | Hosts | Mean overall score |
|---|---|---|
| App, passes P4 | 50 | 94.5 |
| App, answers 200, fails P4 | 14 | 53.8 |
| App, 404 on both paths | 203 | 50.2 |
| Non-app, passes P4 | 83 | 72.5 |
| Non-app, 404 on both paths (info) | 304 | 59.6 |
| Non-app, blocked or errored | 92 | 24.2 |

App hosts that pass P4 average 94.5. App hosts that do not average about 50. Do not read that as "publish OAuth metadata and gain 44 points". P4 is worth 4 points. The hosts that publish OAuth metadata are mostly hosts that publish a lot: 50 of 50 app passes also pass P1. These are sites run by teams that treat agents as a client. P4 marks them; it does not cause the score.

## Reading your own P4 line

The same evidence string means different things depending on who you are. Use this table with the E1 line from the same scan.

| What you see | What it most likely means | What to do |
|---|---|---|
| Info, `404, 404` | Not an app, no files, no penalty | Nothing. Do not publish an empty file |
| Fail, `404, 404` | The scanner took the site for an app and found no files | Publish RFC 9728 metadata if you protect an API; otherwise treat it as the scanner's limit |
| Fail or info, `200, 200`, and E1 fails | A catch-all host serving its shell | Fix the soft 404 first, then re-scan |
| Fail or info, `200, 200`, and E1 passes | Real responses the check does not accept | Fetch the file and check it is JSON with the fields RFC 9728 requires |
| Info, `403`, `429` or `530` | The scanner was blocked or rate-limited | Allow the scanner, or accept that no reading was possible |
| Pass | Either file answered acceptably | Keep the authorization server's own file in sync |

About the 429 rows. Four app hosts fail P4 with `429, 429` and 17 non-apps show info with the same string. Those hosts throttled our scanner, which is a reading of the host's rate limit, not of its metadata. The [determinism self-audit](https://aiscan.site/blog/aiscan-check-determinism-self-audit) found the same pattern on other checks.

## What changed since the queue figures of 2 Nov

The queue entry for this study, written on 2 Nov from 799 hosts, counted 132 passes, 231 fails and 436 info. Today's corpus has 806 hosts and 133, 233 and 440. Seven more hosts entered the corpus and the shape did not move: the pass share is 16.5% in both. The "200 but fail" group grew from 12 to 14. Two more hosts in two days is too few to call a trend, and a rescan of one host can move it between groups, so treat 12 and 14 as the same finding.

## What AIScan cannot see here

- **The body.** Whether the document is valid JSON, names a real issuer, or matches RFC 9728's required `resource` field is not stored.
- **Whether the site has an authenticated API.** `isApp` is inferred from the page. A site with a login and no public API is still scored as an app.
- **The issuer's own file.** P4 requests the file on the host. If your authorization server is a hosted provider, its RFC 8414 file lives on the provider's domain and is outside this check.
- **Intent.** A fail on a site with no API is the scanner's limit, as [the earlier census](https://aiscan.site/blog/well-known-agent-files-corpus) also said.

## If you want to be in the 133

If your site really does protect an API, the work is small and the steps are in [OAuth Discovery for AI Agents](https://aiscan.site/blog/oauth-discovery-for-agents). The short version: serve a JSON document at `/.well-known/oauth-protected-resource` with a `resource` field and an `authorization_servers` array, return `application/json`, and make sure unknown paths return a real 404. If your API is an MCP server, the path-inserted form applies, and [Publish an MCP Server Card](https://aiscan.site/blog/publish-mcp-server-card) covers the sibling file. For a view of how agents reach a public MCP endpoint in practice, see [67 days of who calls our MCP server](https://aiscan.site/blog/public-mcp-server-usage-60-days).

Check by hand, second to the scan:

```bash
curl -s -o /dev/null -w '%{http_code} %{content_type}\n' https://yoursite.com/.well-known/oauth-protected-resource
curl -s -o /dev/null -w '%{http_code}\n' https://yoursite.com/.well-known/zz-not-a-real-file
```

The first line should be `200 application/json` (or a 404 if you have no protected API). The second must be `404`. If the second prints 200, your host is a soft-404 host, and no well-known file on it can be trusted by a client until that is fixed.

If your site has no API and no sign-in, P4 showing info or a fail is not a gap. Do not publish an empty document to turn the line green.

## Next action

Run the scan, then read P4 and E1 together. If E1 fails, fix the soft 404 first, since it undermines every well-known probe. Then decide whether you have a protected API at all. The check details are on the [capabilities page](https://aiscan.site/docs/checks/capabilities), and the other agent-readiness walkthroughs are collected at [aiscan.site/guides](https://aiscan.site/guides).

