Check specification

oauth-protected-resource 1.0.0

OAuth Protected Resource

Validates RFC 9728 protected-resource metadata and 401 challenge linkage when OAuth-protected resources are claimed or exposed.

Assessment Suite
2026.06.10
Maturity
Emerging recommendation
Category
Agent Ease of Use
Subcategory
Auth Discovery

1. Abstract

Publish OAuth Protected Resource Metadata for OAuth-protected APIs and MCP resources so clients can identify the resource and its authorization servers.

Protected-resource metadata tells agents which API/resource is locked, which authorization servers can issue tokens for it, and how a 401 challenge maps back to the correct resource.

2. Classification

Check ID
oauth-protected-resource
Check version
1.0.0
Package path
lib/checks/oauth-protected-resource/versions/1.0.0
Category
Agent Ease of Use
Subcategory
Auth
Check group
Auth Discovery
Check group ID
auth-discovery
Maturity
Emerging recommendation
Scope
site
Check weight
1

3. Input And Output Contracts

Resources inspected
/.well-known/oauth-protected-resource, WWW-Authenticate: resource_metadata

4. Scoring Semantics

Step IDTitleWeightDescription
applicabilityDetect protected-resource applicability0.15Apply only when protected-resource metadata is found or OAuth-protected resource support is claimed.
discoverDiscover metadata candidates0.1Build root, path-specific, linked, and challenge-derived protected-resource metadata candidates.
fetchFetch protected-resource metadata0.2Fetch a protected-resource metadata document from a registered or advertised candidate URL.
metadataValidate metadata shape0.2Validate RFC 9728 required fields and optional registered metadata field shapes.
resource-identityValidate resource identity0.15Confirm metadata resource matches the candidate or challenged protected resource identifier.
authorization-serversValidate authorization servers0.1Validate authorization server issuer URLs, with stricter requirements for MCP/agent OAuth resources.
protected-route-challengeValidate protected resource challenge0.1Confirm protected endpoints return 401 challenges with RFC 9728 resource_metadata linkage when discoverable.

5. Package Documentation

OAuth Protected Resource Check v1.0.0

Status

Abstract

This check validates RFC 9728 OAuth Protected Resource Metadata when a site exposes or claims an OAuth-protected API, MCP endpoint, or agent-facing protected resource. It fetches registered well-known metadata candidates, validates the protected resource identity, validates authorization server issuer hints, and probes discoverable protected routes for WWW-Authenticate challenges containing resource_metadata.

The check is evidence-based. Generic login, Google sign-in, email/password, dashboard API-key generation, and generic bearer API keys do not by themselves make this check applicable.

Motivation

OAuth/OIDC discovery tells a client where the authorization server is. Protected-resource metadata tells the client what protected API/resource it is trying to access and which authorization servers can issue tokens for that resource.

This is especially important for agents and MCP clients because they need to distinguish the locked resource from the login provider, request audience-restricted tokens, and avoid accepting tokens minted for the wrong API.

Normative Model

The check recognizes the RFC 9728 well-known path:

  • /.well-known/oauth-protected-resource

For path-specific resources, RFC 9728 inserts the well-known path before the resource path. For example:

  • Resource https://api.example.com uses https://api.example.com/.well-known/oauth-protected-resource.
  • Resource https://api.example.com/mcp uses https://api.example.com/.well-known/oauth-protected-resource/mcp.

The base RFC 9728 profile requires:

  • resource: HTTPS URL with no fragment.

The following are optional in base RFC 9728, but useful evidence:

  • authorization_servers
  • scopes_supported
  • bearer_methods_supported
  • jwks_uri
  • resource documentation/policy/TOS URLs
  • DPoP and mTLS metadata
  • signed_metadata

For MCP/agent OAuth protected-resource scenarios, the check applies a stricter profile: authorization_servers is required because MCP clients depend on it to discover authorization server locations.

Applicability

The check is applicable when at least one of these is true:

  • a protected-resource metadata document is fetched,
  • the homepage, headers, or links reference oauth-protected-resource,
  • WWW-Authenticate contains resource_metadata,
  • MCP metadata or page text claims OAuth-protected MCP/API access,
  • OpenAPI/API docs/page text claim OAuth-protected API resources,
  • linked metadata advertises RFC 9728 protected-resource metadata.

The check is not applicable when the only signals are:

  • login forms,
  • Google sign-in,
  • email/password auth,
  • account pages,
  • API-key settings,
  • generic Authorization: Bearer <api_key> examples,
  • or 401 responses without RFC 9728 resource_metadata.

Pass Criteria

The check passes when:

  • a metadata candidate is fetched successfully,
  • the response is JSON or +json,
  • resource is an HTTPS URL without a fragment,
  • resource exactly matches the resource identifier represented by the metadata URL,
  • authorization_servers, when required or present, is a non-empty array of HTTPS issuer URLs,
  • optional registered fields have valid shapes,
  • and a protected route, when discoverable, returns a 401 challenge with resource_metadata pointing to the metadata document.

Warning Criteria

Warnings include:

  • generic login, account, dashboard, API-key, or bearer-token examples are present but no RFC 9728 applicability signal is found
  • metadata is present but optional fields such as scopes, bearer methods, JWKS URI, documentation, DPoP, mTLS, or policy URLs are incomplete
  • a protected route cannot be discovered for challenge probing
  • a 401 challenge is present but lacks enough information to prove exact metadata binding
  • browser/client usability metadata such as CORS or cache guidance is weak but the core document is valid

Failure Criteria

Failures include:

  • the site claims RFC 9728, OAuth-protected API, OAuth-protected MCP, or protected-resource metadata support but no metadata candidate is fetchable
  • a metadata candidate is fetched but is not JSON-compatible or valid JSON
  • resource is missing, not HTTPS, contains a fragment, or does not match the resource identifier represented by the metadata URL
  • required or present authorization_servers is missing, empty, malformed, or contains non-HTTPS issuer URLs
  • registered optional fields have invalid shapes
  • a discovered protected route returns a WWW-Authenticate challenge whose resource_metadata is missing, malformed, or does not point to the metadata document
  • public metadata exposes secrets, tokens, cookies, private keys, or credential-bearing URLs

Evidence Model

The result emits:

  • applicability signals and generic auth signals,
  • metadata candidates and their sources,
  • candidate resource identifiers,
  • fetch status, content type, and response length,
  • parsed resource,
  • resource identity match result,
  • authorization server issuer count and sanitized URLs,
  • optional field summaries such as scopes, bearer methods, JWKS URI, DPoP, resource name/docs, and signed metadata presence,
  • challenge probe results including scheme, resource_metadata, scope, status code, and match status,
  • no tokens, cookies, API keys, authorization header values beyond sanitized challenge metadata, or full signed metadata/JWT payloads.

Validation/Scoring Steps

  • applicability (0.15): decide whether RFC 9728 is claimed or discovered.
  • discover (0.10): build root, path-specific, linked, and challenge-derived metadata candidates.
  • fetch (0.20): fetch a protected-resource metadata document.
  • metadata (0.20): validate RFC 9728 shape and optional registered fields.
  • resource-identity (0.15): verify metadata resource matches the expected protected resource identifier.
  • authorization-servers (0.10): validate issuer hints, stricter for MCP/agent OAuth resources.
  • protected-route-challenge (0.10): probe discoverable protected routes for WWW-Authenticate with resource_metadata.

Standard Behavior

Missing metadata is not_applicable unless RFC 9728 or OAuth-protected resource support is claimed. If metadata is found, the check validates it even without visible homepage auth signals.

For base RFC 9728 metadata, missing authorization_servers is a warning. For MCP/agent OAuth protected resources, missing authorization_servers is a failure.

If a protected route returns 401 but omits resource_metadata, the check fails because the protected route did not prove RFC 9728 linkage. If no protected route can be safely probed, otherwise valid metadata produces a warning rather than a failure.

Non-Standard And Real-World Behavior

Many SaaS products use dashboard-generated API keys. That is an auth mechanism, but it is not OAuth Protected Resource Metadata. Those sites should publish clear API-key docs, OpenAPI security schemes, API catalog entries, or auth.md, not RFC 9728 metadata unless they operate OAuth-protected resources.

MCP servers are stricter than base RFC 9728 because MCP clients need protected-resource metadata to bootstrap authorization server discovery and audience-restricted token requests.

Non-Goals And Limitations

  • The check does not complete an OAuth flow.
  • The check does not prove every protected route on the site is linked correctly.
  • The check does not validate signed metadata cryptographically.
  • The check does not replace OAuth/OIDC authorization-server discovery.
  • The check does not require API-key-only products to publish protected-resource metadata.

References

Source: lib/checks/oauth-protected-resource/versions/1.0.0/docs.md

6. Version Changelog

oauth-protected-resource v1.0.0 Changelog

  • Changed applicability from generic auth/login signals to RFC 9728 claim or discovery evidence.
  • Added root, path-specific, linked, and challenge-derived metadata candidate discovery.
  • Added profile-aware handling for base RFC 9728 versus stricter MCP/agent OAuth protected-resource expectations.
  • Treated authorization_servers as optional for base RFC 9728 and required for MCP/agent OAuth protected resources.
  • Tightened WWW-Authenticate validation to require RFC 9728 resource_metadata linkage for protected-route proof.

Source: lib/checks/oauth-protected-resource/versions/1.0.0/changelog.md