GET /.well-known/oauth-protected-resource
Fourth sibling in the discovery quartet (OIDC + AS + agent-card + this). RFC 9728 Protected Resource Metadata describes the resource-server side of the OAuth dance. The default mode joins the conflicting-discovery group; an agent walking all four wells-known finds four contradictory authority claims to reconcile.
curl -i '{url}'
# OAuth Protected Resource Metadata is JSON; just parse and inspect.
# RFC 9728 §3 requires resource == the URL the document was served
# from, so verify that explicitly.
import urllib.request, json
url = "{url}"
raw = urllib.request.urlopen(url).read()
doc = json.loads(raw)
print("resource: ", doc.get("resource"))
print("authorization_servers: ", doc.get("authorization_servers"))
print("bearer_methods_supported:", doc.get("bearer_methods_supported"))
print("Matches served URL: ", doc.get("resource") in url)
const res = await fetch("{url}");
const doc = await res.json();
console.log("Mode:", res.headers.get("X-Chaos-Opr-Mode"));
console.log("Note:", res.headers.get("X-Chaos-Opr-Note"));
console.log("resource:", doc.resource);
console.log("AS: ", doc.authorization_servers);
console.log("bearer: ", doc.bearer_methods_supported);
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
resp, _ := http.Get("{url}")
defer resp.Body.Close()
raw, _ := io.ReadAll(resp.Body)
var doc map[string]any
json.Unmarshal(raw, &doc)
fmt.Println("Mode: ", resp.Header.Get("X-Chaos-Opr-Mode"))
fmt.Println("resource:", doc["resource"])
fmt.Println("AS: ", doc["authorization_servers"])
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
// serde_json = "1"
fn main() -> Result<(), Box> {
let doc: serde_json::Value = reqwest::blocking::get("{url}")?.json()?;
println!("resource: {}", doc["resource"]);
println!("authorization_servers: {}", doc["authorization_servers"]);
println!("bearer_methods_supported: {}", doc["bearer_methods_supported"]);
Ok(())
}
// Requires Jackson.
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.*;
public class OauthProtectedResource {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("{url}")).build();
var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
var doc = new ObjectMapper().readTree(resp.body());
System.out.println("Mode: " + resp.headers().firstValue("X-Chaos-Opr-Mode").orElse(""));
System.out.println("resource: " + doc.get("resource"));
System.out.println("AS: " + doc.get("authorization_servers"));
}
}
using System.Text.Json;
using var client = new HttpClient();
var resp = await client.GetAsync("{url}");
var raw = await resp.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(raw);
Console.WriteLine($"Mode: {resp.Headers.GetValues("X-Chaos-Opr-Mode").First()}");
Console.WriteLine($"resource: {doc.RootElement.GetProperty("resource")}");
Console.WriteLine($"AS: {doc.RootElement.GetProperty("authorization_servers")}");
require "net/http"
require "json"
url = "{url}"
resp = Net::HTTP.get_response(URI(url))
doc = JSON.parse(resp.body)
puts "Mode: #{resp['X-Chaos-Opr-Mode']}"
puts "resource: #{doc['resource']}"
puts "AS: #{doc['authorization_servers']}"
puts "Matches URL? #{url.start_with?(doc['resource'])}"
$resp = Invoke-WebRequest -Uri '{url}' -SkipHttpErrorCheck
$resp.Headers['X-Chaos-Opr-Mode']
$doc = $resp.Content | ConvertFrom-Json
"resource: $($doc.resource)"
"AS: $($doc.authorization_servers -join ', ')"
"bearer: $($doc.bearer_methods_supported -join ', ')"