<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     ipr="trust200902"
     docName="draft-kodden-oidfed-admin-00"
     category="info"
     submissionType="independent"
     tocInclude="true"
     sortRefs="true"
     symRefs="true"
     version="3"
     xml:lang="en">

  <front>
    <title abbrev="OIDFed Node Admin">OpenID Federation Node Administration Protocol</title>
    <seriesInfo name="Internet-Draft" value="draft-kodden-oidfed-admin-00"/>
    <author fullname="H.M. Kodden" initials="H.M." surname="Kodden" role="editor">
      <organization>SURF</organization>
      <address>
        <email>harry.kodden@surf.nl</email>
        <uri>https://orcid.org/0009-0009-0037-3046</uri>
      </address>
    </author>
    <date year="2026" month="August" day="29"/>
    <area>Security</area>
    <workgroup>Independent Submission</workgroup>
    <keyword>OpenID Federation</keyword>
    <keyword>administration</keyword>
    <keyword>HTTP</keyword>
    <keyword>Entity Configuration</keyword>
    <keyword>Trust Mark</keyword>
    <abstract>
      <t>
        This document specifies a compact HTTP application programming
        interface for administering an OpenID Federation node. The
        interface manages the operator-controlled inputs from which a
        node produces the Entity Configurations, Subordinate Statements,
        Trust Marks, and Federation Entity Keys defined by OpenID
        Federation 1.1. It does not replace the public federation
        protocol. It is the management plane used by operators and
        control-plane software to configure what that protocol publishes.
      </t>
      <t>
        The design is document-oriented. Operators read and write the
        same JSON objects OpenID Federation already defines, rather than
        a large set of per-claim endpoints. Five resources cover node
        identity, Federation Entity Keys, the node's Entity
        Configuration, Immediate Subordinates, and Trust Mark issuance.
      </t>
    </abstract>
  </front>

  <middle>
    <section anchor="intro" numbered="true">
      <name>Introduction</name>
      <t>
        OpenID Federation 1.1 <xref target="OIDF.Federation"/> defines
        how Federation Entities publish signed Entity Statements, build
        Trust Chains, apply metadata policies, and issue Trust Marks.
        Those mechanisms are the public protocol plane: any relying
        party on the Internet can fetch
        <tt>/.well-known/openid-federation</tt>, call
        <tt>federation_fetch_endpoint</tt>, and resolve a Trust Chain.
      </t>
      <t>
        The specification does not define how an operator configures a
        node so that those public artifacts exist. In practice, Trust
        Anchors, Intermediate Entities, Leaf Entities, and Trust Mark
        Issuers are administered through vendor-specific HTTP APIs.
        Existing implementations
        <xref target="Sphereon.Admin"/>,
        <xref target="GEANT.Admin"/>,
        <xref target="Gateway.Admin"/>, and
        <xref target="SURF.OIDFed"/>
        expose dozens of fine-grained endpoints, one for each nested
        claim. That style is convenient for some user interfaces. It is
        a poor protocol: it duplicates the OpenID Federation data model,
        drifts as the federation specification evolves, and forces every
        control plane to learn a different surface.
      </t>
      <t>
        This document specifies a single, compact administration
        protocol that is strictly aligned with OpenID Federation 1.1:
      </t>
      <ul>
        <li>
          The protocol plane remains exactly as defined in
          <xref target="OIDF.Federation"/>. This document never
          redefines Entity Statement claims, metadata policy operators,
          Trust Mark claims, or federation endpoints.
        </li>
        <li>
          The administration plane writes the inputs from which the
          node (re)signs and publishes those artifacts.
        </li>
        <li>
          Resources correspond to independently life-cycled objects:
          the node itself, Federation Entity Keys, the Entity
          Configuration document, Immediate Subordinates, and Trust
          Mark issuance records.
        </li>
        <li>
          Partial updates use JSON Merge Patch <xref target="RFC7396"/>
          against those documents. Fine-grained claim URLs are
          unnecessary.
        </li>
      </ul>
      <t>
        The result is a small, implementable API that Leaf nodes,
        Intermediates, Trust Anchors, and Trust Mark Issuers can share,
        advertising which resources they actually support.
      </t>

      <section anchor="applicability">
        <name>Applicability</name>
        <t>This protocol is intended for:</t>
        <ul>
          <li>federation operators administering a Trust Anchor or Intermediate;</li>
          <li>organization administrators administering a Leaf Entity;</li>
          <li>Trust Mark Issuers granting and revoking Trust Marks;</li>
          <li>
            control-plane software, registries, and operator user
            interfaces that manage one or more nodes.
          </li>
        </ul>
        <t>
          This protocol is not intended to replace Trust Chain
          resolution, Automatic or Explicit Registration, or any other
          public federation endpoint. Clients that only need to consume
          federation data MUST use <xref target="OIDF.Federation"/> and
          MUST NOT require this API.
        </t>
      </section>

      <section anchor="conventions-bcp14">
        <name>Notational Conventions</name>
        <t>
          The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
          "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
          "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
          "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
          "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
          "<bcp14>OPTIONAL</bcp14>" in this document are to be
          interpreted as described in BCP 14 <xref target="RFC2119"/>
          <xref target="RFC8174"/> when, and only when, they appear in
          all capitals, as shown here.
        </t>
        <t>
          JSON object member names are case-sensitive. This document
          uses the JSON data model of <xref target="RFC8259"/>. HTTP
          terminology follows <xref target="RFC9110"/>. URI syntax
          follows <xref target="RFC3986"/>.
        </t>
        <t>Unless stated otherwise, examples are non-normative.</t>
      </section>
    </section>

    <section anchor="terminology">
      <name>Terminology</name>
      <t>
        This document uses the terms Entity, Entity Identifier, Entity
        Configuration, Entity Statement, Entity Type, Federation Entity
        Keys, Immediate Superior, Immediate Subordinate, Intermediate
        Entity, Leaf Entity, metadata, metadata policy, Subordinate
        Statement, Trust Anchor, Trust Chain, Trust Mark, Trust Mark
        Issuer, and Trust Mark Owner as defined in
        <xref target="OIDF.Federation"/>.
      </t>
      <t>This document also uses the following terms:</t>
      <dl newline="true">
        <dt>Administration API:</dt>
        <dd>The HTTP API specified in this document.</dd>
        <dt>Administration Server:</dt>
        <dd>
          The HTTP origin that serves the Administration API for one
          Federation Entity (one node).
        </dd>
        <dt>Node:</dt>
        <dd>
          A deployed Federation Entity that publishes an Entity
          Configuration and, depending on role, Subordinate Statements
          and Trust Marks.
        </dd>
        <dt>Admin Document:</dt>
        <dd>
          A JSON object that an operator reads or writes through the
          Administration API. An Admin Document contains OpenID
          Federation claims plus a small set of administration-only
          members (<xref target="admin-members"/>).
        </dd>
        <dt>Protocol Plane:</dt>
        <dd>
          The public OpenID Federation endpoints defined in Sections 8
          and 9 of <xref target="OIDF.Federation"/>, including
          <tt>/.well-known/openid-federation</tt>.
        </dd>
        <dt>Status:</dt>
        <dd>
          An administration-only life-cycle value that controls whether
          a configured object is currently published on the Protocol
          Plane.
        </dd>
      </dl>
    </section>

    <section anchor="architecture">
      <name>Architecture</name>
      <t>
        A node has two HTTP surfaces. The Protocol Plane is defined
        entirely by <xref target="OIDF.Federation"/>. It serves Entity
        Configurations, Subordinate Statements, Trust Marks, and related
        federation endpoints to unauthenticated or
        <tt>private_key_jwt</tt>-authenticated federation participants.
      </t>
      <t>
        The Administration Plane is defined by this document. It is a
        confidential HTTP API used by operators and control-plane
        clients to create, update, suspend, and revoke the inputs from
        which the Protocol Plane is generated.
      </t>
      <figure anchor="fig-planes">
        <name>Administration Plane and Protocol Plane</name>
        <artwork type="ascii-art"><![CDATA[
 Operator / Control Plane
          |
          |  Administration API (this document)
          |  authenticated, confidential
          v
   +------------+         signs         +----------------+
   | Admin docs | --------------------> | Protocol Plane |
   | Keys       |  Entity Config        | /.well-known/  |
   | Status     |  Subord. Statement    | fetch / list   |
   |            |  Trust Mark JWT       | resolve / TM   |
   +------------+                       +----------------+
          ^                                     |
          |                                     v
   Administration Server             Federation participants
]]></artwork>
      </figure>
      <t>
        A successful mutating Administration API request MUST leave the
        Protocol Plane consistent with the resulting Admin Documents
        before the success response is returned, with the exception of
        key rollover grace periods described in
        <xref target="keys"/>. Implementations MAY sign new Entity
        Statements lazily, provided that the next Protocol Plane
        response reflects the update.
      </t>
      <t>
        This document does not specify multi-node orchestration,
        operator identity providers, or a federation-wide registry.
        Those are deployment concerns (<xref target="deployment"/>).
      </t>
    </section>

    <section anchor="bootstrap">
      <name>Node Initialization</name>
      <t>
        A node is initialized when it has an Entity Identifier and at
        least one signing-capable Federation Entity Key (the server
        holds the private key or can invoke a KMS to use it).
      </t>
      <t>
        The Entity Identifier is established by local configuration
        (for example a configuration file or container image) or by
        the first successful <tt>PUT {base}/configuration</tt> whose
        body includes <tt>entity_id</tt>. After initialization the
        server MUST reject any write that would change
        <tt>entity_id</tt> (<tt>400</tt> with problem type
        <tt>invalid_request</tt>).
      </t>
      <t>
        <tt>GET {base}</tt> MUST succeed once the Administration
        Server is listening, including before initialization. Before
        the Entity Identifier is set, the Node document omits
        <tt>entity_id</tt> and <tt>signing_kid</tt>.
      </t>
      <t>
        Requests that require a signature — publishing an Entity
        Configuration or Subordinate Statement, or issuing a Trust
        Mark — MUST fail with <tt>409</tt> and problem type
        <tt>not_initialized</tt> until initialization is complete.
      </t>
    </section>

    <section anchor="roles">
      <name>Node Roles and Capabilities</name>
      <t>
        A node plays one or more of the roles defined by
        <xref target="OIDF.Federation"/>:
      </t>
      <ul>
        <li>
          <tt>trust_anchor</tt> — has Immediate Subordinates and no
          Superior (or is treated as a Trust Anchor by its federation).
        </li>
        <li>
          <tt>intermediate</tt> — has both Immediate Superiors and
          Immediate Subordinates.
        </li>
        <li>
          <tt>leaf</tt> — has Immediate Superiors and no Immediate
          Subordinates.
        </li>
        <li>
          <tt>trust_mark_issuer</tt> — issues Trust Marks.
        </li>
        <li>
          <tt>resolver</tt> — publishes
          <tt>federation_resolve_endpoint</tt>.
        </li>
      </ul>
      <t>
        The <tt>resolver</tt> role means the node publishes
        <tt>federation_resolve_endpoint</tt> in its Entity
        Configuration, typically under
        <tt>metadata.federation_entity</tt>. This document does not
        define administration of resolver state such as cached Trust
        Chains or the set of Trust Anchors a resolver uses. Those
        remain Protocol Plane behavior and local configuration
        (<xref target="OIDF.Federation"/>, Sections 8.3 and 10.6). A
        node that is only a resolver MUST implement Node, Keys, and
        Entity Configuration. It MUST return
        <tt>unsupported_resource</tt> for Subordinates and Trust Marks
        unless it also plays a Superior or issuer role.
      </t>
      <t>
        Roles determine which Administration API resources a node MUST
        implement. A node that is only a Leaf MUST implement Node,
        Keys, and Entity Configuration. A node that is a Superior MUST
        additionally implement Subordinates. A node that issues Trust
        Marks MUST implement Trust Marks.
      </t>
      <t>
        The node advertises implemented resources in the Node resource
        (<xref target="node"/>). Clients MUST query that resource and
        MUST NOT assume that every node implements every resource.
      </t>
    </section>

    <section anchor="overview">
      <name>Protocol Overview</name>
      <t>
        The Administration API is a set of HTTPS resources under a
        single base path. The default base path is <tt>/admin/v1</tt>.
        Servers MAY use a different base path; clients discover it from
        the Node resource or from deployment configuration.
      </t>
      <t>Five resources constitute the API:</t>
      <table anchor="tab-resources">
        <name>Administration API resources</name>
        <thead>
          <tr>
            <th>Resource</th>
            <th>Path</th>
            <th>Purpose</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Node</td>
            <td><tt>{base}</tt></td>
            <td>Identity, roles, capabilities</td>
          </tr>
          <tr>
            <td>Keys</td>
            <td><tt>{base}/keys</tt></td>
            <td>Federation Entity Keys</td>
          </tr>
          <tr>
            <td>Entity Configuration</td>
            <td><tt>{base}/configuration</tt></td>
            <td>Self-asserted Admin Document</td>
          </tr>
          <tr>
            <td>Subordinates</td>
            <td><tt>{base}/subordinates</tt></td>
            <td>Immediate Subordinate Admin Documents</td>
          </tr>
          <tr>
            <td>Trust Marks</td>
            <td><tt>{base}/trust-marks</tt></td>
            <td>Trust Mark issuance and subject grants</td>
          </tr>
        </tbody>
      </table>
      <t>
        Each collection uses the HTTP methods in
        <xref target="RFC9110"/> with the following uniform meaning:
      </t>
      <ul>
        <li><tt>GET</tt> — read a document or list members.</li>
        <li><tt>POST</tt> — create a member (or invoke a controller such as rotate).</li>
        <li><tt>PUT</tt> — replace a document.</li>
        <li>
          <tt>PATCH</tt> — merge-patch a document
          (<xref target="RFC5789"/>, <xref target="RFC7396"/>).
        </li>
        <li><tt>DELETE</tt> — remove a member and stop publishing it.</li>
      </ul>
      <t>
        Signed protocol artifacts are available as sub-resources that
        return the JWT the node currently publishes:
      </t>
      <ul>
        <li><tt>GET {base}/configuration/statement</tt></li>
        <li><tt>GET {base}/subordinates/{entity_id}/statement</tt></li>
        <li><tt>GET {base}/trust-marks/{type}/subjects/{entity_id}/token</tt></li>
      </ul>
      <t>
        That is the entire API. Nested claim paths such as
        <tt>/subordinates/{id}/metadata-policies/{entityType}/{claim}/{operator}</tt>
        are deliberately omitted. Operators who need to change one
        field send a JSON Merge Patch against the document that
        contains it.
      </t>
    </section>

    <section anchor="ids-and-paths">
      <name>Identifiers and Paths</name>
      <t>
        A node's Entity Identifier is the <tt>iss</tt> / <tt>sub</tt>
        value of its Entity Configuration. It is immutable for the
        lifetime of the node after initialization.
      </t>
      <t>
        Immediate Subordinates and Trust Mark subjects are addressed by
        their Entity Identifier. Trust Mark types are addressed by
        their <tt>trust_mark_type</tt> URI.
      </t>
      <t>
        When an Entity Identifier or Trust Mark type appears as a path
        segment, it MUST be percent-encoded as a single segment per
        <xref target="RFC3986"/>. Clients MUST encode the entire
        identifier, including scheme, <tt>:</tt>, <tt>/</tt>, and
        <tt>?</tt>. Servers MUST decode exactly one path segment.
      </t>
      <figure>
        <name>Percent-encoded subordinate path</name>
        <artwork type="http-message"><![CDATA[
GET /admin/v1/subordinates/https%3A%2F%2Fop.example.org
]]></artwork>
      </figure>
      <t>
        Servers MAY also accept an opaque server-assigned
        <tt>id</tt> as an alias. If they do, the Admin Document MUST
        still include the <tt>entity_id</tt> member, and listing
        responses MUST include both identifiers.
      </t>
      <t>
        JSON Web Key <tt>kid</tt> values used as path segments MUST be
        percent-encoded.
      </t>
    </section>

    <section anchor="auth">
      <name>Authentication and Transport</name>
      <t>
        The Administration API MUST be served over HTTPS
        <xref target="RFC9110"/>. Servers and clients MUST verify
        TLS server identity as specified in
        <xref target="RFC9525"/>.
      </t>
      <t>
        Every request except <tt>OPTIONS</tt> CORS preflight (if
        offered) MUST be authenticated. This specification does not
        mandate a single authentication scheme. Servers MUST support at
        least one of:
      </t>
      <ul>
        <li>
          OAuth 2.0 Bearer tokens <xref target="RFC6749"/>
          <xref target="RFC6750"/>;
        </li>
        <li>
          HTTP Message Signatures <xref target="RFC9421"/> using a
          Federation Entity Key, when the client is itself a
          Federation Entity.
        </li>
      </ul>
      <t>
        Servers MAY additionally support mutual TLS or HTTP Basic
        authentication for constrained deployments. Servers MUST NOT
        accept unauthenticated mutating requests.
      </t>
      <t>
        Authorization — which operators may create subordinates, rotate
        keys, or issue Trust Marks — is out of scope. Deployments
        SHOULD apply least-privilege roles and SHOULD record an audit
        trail of mutating requests.
      </t>
    </section>

    <section anchor="conventions">
      <name>Common Conventions</name>

      <section>
        <name>Media Types</name>
        <t>Unless a section specifies otherwise:</t>
        <ul>
          <li>
            Request and response bodies use
            <tt>application/json</tt> <xref target="RFC8259"/>.
          </li>
          <li>
            <tt>PATCH</tt> requests use
            <tt>application/merge-patch+json</tt>
            <xref target="RFC7396"/>.
          </li>
          <li>
            Signed Entity Statements are returned as
            <tt>application/entity-statement+jwt</tt>
            <xref target="OIDF.Federation"/>.
          </li>
          <li>
            Signed Trust Marks are returned as
            <tt>application/trust-mark+jwt</tt>
            <xref target="OIDF.Federation"/>.
          </li>
          <li>
            Errors use <tt>application/problem+json</tt>
            <xref target="RFC9457"/> (<xref target="errors"/>).
          </li>
        </ul>
        <t>
          Except in JSON Merge Patch request bodies
          (<xref target="RFC7396"/>), Admin Documents, Key Documents,
          list responses, and error bodies MUST NOT use the JSON value
          <tt>null</tt>. A member that does not apply is omitted. This
          matches the prohibition on <tt>null</tt> in Entity metadata
          (<xref target="OIDF.Federation"/>, Section 5).
        </t>
      </section>

      <section anchor="admin-members">
        <name>Administration-Only Members</name>
        <t>
          Admin Documents MAY contain the following members in addition
          to the OpenID Federation claims of the corresponding
          artifact. These members MUST NOT appear in published Entity
          Statements or Trust Marks.
        </t>
        <dl newline="true">
          <dt>entity_id (string):</dt>
          <dd>
            The Entity Identifier. REQUIRED on Subordinate and Trust
            Mark subject documents. On the Entity Configuration
            document it equals the node's Entity Identifier.
          </dd>
          <dt>status (string):</dt>
          <dd>
            For subordinates and Trust Mark grants: one of
            <tt>pending</tt>, <tt>active</tt>, <tt>suspended</tt>,
            or <tt>revoked</tt>. Default <tt>active</tt>. For keys:
            one of <tt>active</tt>, <tt>retiring</tt>, or
            <tt>revoked</tt>. See <xref target="status"/>.
          </dd>
          <dt>lifetime (number):</dt>
          <dd>
            Suggested lifetime in seconds used by the server when
            computing the <tt>exp</tt> claim of the next signed
            artifact. If omitted, the server uses a locally configured
            default.
          </dd>
          <dt>updated_at (number):</dt>
          <dd>
            Seconds since the epoch at which the Admin Document was
            last written. Assigned by the server. Clients MUST ignore
            this member on write.
          </dd>
          <dt>etag (string):</dt>
          <dd>
            Opaque revision tag. Assigned by the server. Clients MUST
            ignore this member on write and SHOULD send it as
            <tt>If-Match</tt> on subsequent writes.
          </dd>
        </dl>
        <t>
          Unknown members that are not OpenID Federation claims and
          are not defined here MUST be ignored on read and MUST be
          preserved across <tt>PATCH</tt> if the server stored them,
          unless the patch sets the member to <tt>null</tt>.
        </t>
      </section>

      <section anchor="status">
        <name>Status and Publication</name>
        <t>
          <tt>status</tt> controls Protocol Plane visibility. A
          Subordinate Statement or Trust Mark MUST NOT be published
          until live verification has succeeded
          (<xref target="live-verify"/>).
        </t>
        <dl newline="true">
          <dt>pending:</dt>
          <dd>
            Bootstrap state for subordinates and Trust Mark grants
            when the subject is not yet online. The configuration is
            retained. The object MUST NOT be published. Keys do not
            use <tt>pending</tt>.
          </dd>
          <dt>active:</dt>
          <dd>
            The object is published. Subordinates appear in
            <tt>federation_list_endpoint</tt> and are returned by
            <tt>federation_fetch_endpoint</tt>. Trust Marks are issued
            and validate at
            <tt>federation_trust_mark_status_endpoint</tt>. Keys with
            <tt>active</tt> status are eligible for signing and appear
            in the published <tt>jwks</tt>.
          </dd>
          <dt>suspended:</dt>
          <dd>
            The configuration is retained. The object MUST NOT be
            published on the Protocol Plane. Fetch and list behave as
            if the object did not exist. A later transition to
            <tt>active</tt> republishes it after live verification.
          </dd>
          <dt>revoked:</dt>
          <dd>
            Terminal state. The object MUST NOT be published. A
            subsequent <tt>PUT</tt> or <tt>POST</tt> with the same
            identifier is a new object, not a resurrection of the
            revoked one. Servers MAY retain revoked records for audit.
          </dd>
        </dl>
        <figure>
          <name>Allowed status transitions</name>
          <artwork type="ascii-art"><![CDATA[
  pending --> active <--> suspended
     |          |            |
     +------> revoked <------+
]]></artwork>
        </figure>
        <t>
          <tt>pending</tt> and <tt>suspended</tt> MAY transition to
          <tt>active</tt> only after live verification succeeds.
          <tt>revoked</tt> MUST NOT return to <tt>pending</tt>,
          <tt>active</tt>, or <tt>suspended</tt>. <tt>DELETE</tt> is
          equivalent to transitioning to <tt>revoked</tt> and then
          removing the record from ordinary list results. Servers MAY
          keep <tt>pending</tt> or revoked objects visible in list
          results when the client passes the corresponding
          <tt>status</tt> query.
        </t>
        <t>
          OpenID Federation 1.1 does not define a revocation protocol
          (<xref target="OIDF.Federation"/>, Section 11.4). Status is
          an administration control that causes the node to stop
          publishing the corresponding artifact so that Trust Chains
          expire or fail to refresh.
        </t>
      </section>

      <section>
        <name>Concurrency</name>
        <t>
          Servers MUST return an <tt>ETag</tt> header on every
          successful GET, PUT, POST, and PATCH of an Admin Document.
          Clients SHOULD send <tt>If-Match</tt> on PUT, PATCH, and
          DELETE. If <tt>If-Match</tt> does not match the current
          revision, the server MUST return
          <tt>412 Precondition Failed</tt>.
        </t>
      </section>

      <section>
        <name>Pagination and Filtering</name>
        <t>List endpoints return:</t>
        <sourcecode type="json">{
  "items": [
    {
      "entity_id": "https://op.example.org",
      "status": "active"
    }
  ],
  "next": "LjI"
}</sourcecode>
        <t>
          <tt>limit</tt> (query, positive integer) is OPTIONAL.
          Servers MUST honor values up to an implementation-defined
          maximum and MUST NOT return more items than requested.
          <tt>cursor</tt> (query, string) is OPTIONAL and continues a
          previous page. When no further page exists, the
          <tt>next</tt> member is omitted.
        </t>
        <t>List endpoints MAY support:</t>
        <ul>
          <li><tt>status</tt> — filter by administration status;</li>
          <li>
            <tt>entity_type</tt> — filter subordinates whose
            <tt>metadata</tt> contains that Entity Type Identifier;
          </li>
          <li>
            <tt>q</tt> — implementation-defined substring match on
            <tt>entity_id</tt>.
          </li>
        </ul>
      </section>

      <section>
        <name>JSON Merge Patch</name>
        <t>
          <tt>PATCH</tt> uses JSON Merge Patch
          <xref target="RFC7396"/>. A member set to <tt>null</tt> is
          deleted. Arrays are replaced, not merged. To change one
          element of <tt>authority_hints</tt> or <tt>trust_marks</tt>,
          the client sends the complete replacement array.
        </t>
        <t>
          OpenID Federation objects such as <tt>metadata</tt>,
          <tt>metadata_policy</tt>, and <tt>constraints</tt> are JSON
          objects and therefore merge recursively. This is the intended
          way to change a single metadata parameter or a single policy
          operator.
        </t>
      </section>

      <section anchor="federation-validation">
        <name>Validation Against OpenID Federation</name>
        <t>
          On every write of an Admin Document the server MUST validate
          that the OpenID Federation claims would produce a
          syntactically valid artifact under
          <xref target="OIDF.Federation"/>:
        </t>
        <ul>
          <li>
            Entity Configuration writes: claims in Sections 3.1.1 and
            3.1.2.
          </li>
          <li>
            Subordinate writes: claims in Sections 3.1.1 and 3.1.3,
            including <tt>metadata_policy</tt> (Section 6.1) and
            <tt>constraints</tt> (Section 6.2).
          </li>
          <li>Trust Mark writes: claims in Section 7.1.</li>
        </ul>
        <t>
          The server MUST reject writes that violate those rules with
          <tt>400</tt> and problem type
          <tt>invalid_federation_claim</tt>
          (<xref target="errors"/>). The server MUST NOT accept
          <tt>iss</tt> or <tt>sub</tt> values that conflict with the
          node's Entity Identifier or the subordinate's
          <tt>entity_id</tt>. The server assigns <tt>iss</tt>,
          <tt>sub</tt>, <tt>iat</tt>, and <tt>exp</tt> when it signs.
        </t>
        <t>
          The server MUST reject a Leaf configuration that includes
          <tt>federation_fetch_endpoint</tt> or
          <tt>federation_list_endpoint</tt>, and MUST reject a Superior
          configuration that omits them, consistent with Section 5.1.1
          of <xref target="OIDF.Federation"/>.
        </t>
      </section>

      <section anchor="live-verify">
        <name>Live Verification Before Publication</name>
        <t>
          Claim validation (<xref target="federation-validation"/>) is not
          enough to add another Entity to the federation. A write
          that would publish a Subordinate Statement or issue a Trust
          Mark MUST also live-check the subject before the Protocol
          Plane changes. Keys are local to the node: generate and
          import validate the public JWK and MUST NOT publish private
          material; they have no remote subject to fetch.
        </t>
        <t>
          The server MUST perform live verification when any of the
          following holds:
        </t>
        <ul>
          <li>
            The resulting <tt>status</tt> is <tt>active</tt> and the
            object was not already <tt>active</tt> (create, or
            transition from <tt>pending</tt> or <tt>suspended</tt>).
          </li>
          <li>
            The resulting <tt>status</tt> is <tt>active</tt> and the
            write changes a subordinate's <tt>entity_id</tt> or
            <tt>jwks</tt>.
          </li>
          <li>
            A Trust Mark grant is created or replaced with resulting
            <tt>status</tt> <tt>active</tt>.
          </li>
        </ul>
        <t>
          A metadata-only change to an already-active subordinate
          does not require a new live check. Claim validation still
          applies.
        </t>
        <t>
          Subordinate live verification: the server MUST fetch the
          subject's Entity Configuration and verify that the
          presented <tt>jwks</tt> matches the subject's Federation
          Entity Keys and that the node's Entity Identifier appears
          in the subject's <tt>authority_hints</tt>.
          <tt>naming_constraints</tt> and
          <tt>allowed_entity_types</tt> MUST still be applied when
          present.
        </t>
        <t>
          Trust Mark grant live verification: the server MUST verify
          that a Trust Chain to the subject can be constructed under
          at least one Trust Anchor this node trusts.
        </t>
        <t>
          On failure, including when the subject cannot be reached,
          the server MUST return <tt>422</tt> with problem type
          <tt>subject_mismatch</tt> and MUST NOT publish or replace
          the Protocol Plane artifact. A stored
          <tt>pending</tt> or <tt>suspended</tt> document is left
          unchanged.
        </t>
        <t>
          Query parameter <tt>verify</tt> and body member
          <tt>verify</tt> have the same meaning. They default to
          <tt>true</tt>. If both are present they MUST agree.
          <tt>verify=false</tt> is accepted only when the resulting
          <tt>status</tt> is not <tt>active</tt>; otherwise the
          server MUST return <tt>400</tt> with problem type
          <tt>invalid_request</tt>.
        </t>
        <t>
          If the subject is not yet online, the operator writes
          <tt>status</tt> <tt>pending</tt>. The document is stored
          and MUST NOT be published. <tt>jwks</tt> MAY be omitted
          while pending and is REQUIRED when the subordinate becomes
          <tt>active</tt>. The later transition to <tt>active</tt>
          MUST live-verify.
        </t>
      </section>
    </section>

    <section anchor="node">
      <name>Node Resource</name>
      <section>
        <name>GET {base}</name>
        <t>Returns the node's identity and capabilities.</t>
        <t>Response <tt>200</tt>:</t>
        <sourcecode type="json">{
  "entity_id": "https://ta.example.org",
  "roles": ["trust_anchor", "trust_mark_issuer"],
  "base": "/admin/v1",
  "spec": "draft-kodden-oidfed-admin-00",
  "signing_kid": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs",
  "implementation": {
    "name": "example-node",
    "version": "1.4.2"
  },
  "capabilities": {
    "keys": ["list", "create", "rotate", "delete"],
    "configuration": ["read", "replace", "patch"],
    "subordinates": ["list", "create", "read", "replace",
                     "patch", "delete", "status", "statement"],
    "trust_marks": ["list", "create", "read", "replace",
                    "delete", "grant", "status", "token"]
  }
}</sourcecode>
        <t>
          <tt>roles</tt> MUST be consistent with the Entity Types
          present in the published Entity Configuration.
          <tt>capabilities</tt> lists the operations the server
          implements for each resource. Clients MUST treat a missing
          resource key as "not implemented".
        </t>
        <t>
          <tt>GET {base}</tt> is the capability discovery document.
          There is no separate <tt>/capabilities</tt> resource.
        </t>
      </section>
    </section>

    <section anchor="keys">
      <name>Federation Entity Keys</name>
      <t>
        Federation Entity Keys are the keys whose public halves appear
        in the <tt>jwks</tt> claim of the node's Entity Configuration
        as a JSON Web Key Set <xref target="RFC7517"/> and that sign
        Entity Statements and Trust Marks as JSON Web Signatures
        <xref target="RFC7515"/>
        (<xref target="OIDF.Federation"/>, Sections 3.1.1 and 7).
        Entity Statements and Trust Marks are JWTs
        <xref target="RFC7519"/>.
        Protocol keys carried under Entity Type metadata are not
        managed here; they are ordinary members of <tt>metadata</tt>.
      </t>

      <section>
        <name>Key Document</name>
        <sourcecode type="json">{
  "kid": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs",
  "status": "active",
  "signing": true,
  "alg": "ES256",
  "kty": "EC",
  "public_jwk": {
    "kty": "EC",
    "crv": "P-256",
    "kid": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs",
    "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
    "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"
  },
  "created_at": 1756454400
}</sourcecode>
        <t>
          <tt>kid</tt> SHOULD be the JWK Thumbprint using SHA-256
          <xref target="RFC7638"/>, as recommended by
          <xref target="OIDF.Federation"/>. <tt>public_jwk</tt> MUST
          contain only public members. Private key material MUST NOT
          appear in any Administration API response.
          <tt>not_after</tt> is an OPTIONAL expiration time in
          seconds since the epoch. If the key does not expire, the
          member is omitted.
        </t>
        <t>
          <tt>status</tt> for keys is <tt>active</tt>,
          <tt>retiring</tt>, or <tt>revoked</tt>:
        </t>
        <ul>
          <li>
            <tt>active</tt> — present in the published <tt>jwks</tt>;
            eligible to become the signing key.
          </li>
          <li>
            <tt>retiring</tt> — present in the published
            <tt>jwks</tt>; MUST NOT be newly selected as the signing
            key. It MAY remain the signing key until a rollover
            switch completes (<xref target="rotate"/>). Used during
            rollover (<xref target="OIDF.Federation"/>, Section 11.2).
          </li>
          <li>
            <tt>revoked</tt> — absent from the current <tt>jwks</tt>;
            MAY appear at
            <tt>federation_historical_keys_endpoint</tt>.
          </li>
        </ul>
        <t>
          Exactly one key is the node's signing key at any time, or
          none if no signing-capable key exists. <tt>signing</tt> is
          <tt>true</tt> on that Key Document. The Node document's
          <tt>signing_kid</tt> is that key's <tt>kid</tt>, and is
          omitted when none exists.
        </t>
        <t>
          If several keys are <tt>active</tt> and signing-capable, the
          server MUST choose exactly one as the signing key. It is
          RECOMMENDED that this be the most recently created such key.
          Clients MUST read <tt>signing_kid</tt> or <tt>signing</tt>
          rather than inferring from <tt>status</tt> alone.
        </t>
      </section>

      <section>
        <name>GET {base}/keys</name>
        <t>
          Returns a page of Key Documents. Query <tt>status</tt> MAY
          filter the list.
        </t>
      </section>

      <section>
        <name>POST {base}/keys</name>
        <t>
          Creates a key. The request is one of two shapes. Generate
          (server holds the private key):
        </t>
        <sourcecode type="json">{
  "generate": {
    "kty": "EC",
    "crv": "P-256",
    "alg": "ES256"
  }
}</sourcecode>
        <t>
          Import (private key is held elsewhere; only the public JWK
          is registered):
        </t>
        <sourcecode type="json">{
  "import": {
    "kty": "EC",
    "crv": "P-256",
    "x": "...",
    "y": "...",
    "alg": "ES256"
  }
}</sourcecode>
        <t>
          Response <tt>201</tt> with the Key Document and a
          <tt>Location</tt> header. The new public JWK MUST appear in
          the next published Entity Configuration <tt>jwks</tt>.
        </t>
        <t>
          A newly created key that the server can sign with becomes
          the signing key if none exists; otherwise it is
          <tt>active</tt> with <tt>signing</tt> false. If the node
          has no signing-capable <tt>active</tt> key after this
          request, the server MUST still accept an import, but
          requests that require a signature MUST return <tt>409</tt>
          with problem type <tt>not_initialized</tt> until a signing
          key is available.
        </t>
      </section>

      <section>
        <name>GET {base}/keys/{kid}</name>
        <t>Returns the Key Document. <tt>404</tt> if unknown.</t>
      </section>

      <section>
        <name>DELETE {base}/keys/{kid}</name>
        <t>
          Transitions the key to <tt>revoked</tt> and removes it from
          the published <tt>jwks</tt>. The server MUST reject the
          request with <tt>409</tt> and problem type
          <tt>last_signing_key</tt> if this is the last
          <tt>active</tt> or <tt>retiring</tt> key that can sign.
        </t>
        <t>
          If the deleted key was the signing key and another
          signing-capable <tt>active</tt> key exists, the server MUST
          select a replacement (RECOMMENDED: the most recently
          created) and update <tt>signing_kid</tt>.
        </t>
      </section>

      <section anchor="rotate">
        <name>POST {base}/keys/{kid}/rotate</name>
        <t>
          Performs a Federation key rollover for <tt>{kid}</tt> as
          specified in <xref target="OIDF.Federation"/>, Section 11:
        </t>
        <ol>
          <li>
            Generate or import a new key (request body is the same as
            <tt>POST {base}/keys</tt>).
          </li>
          <li>
            Add the new key to the published <tt>jwks</tt> with
            <tt>status=active</tt>.
          </li>
          <li>
            Set the old key's <tt>status</tt> to <tt>retiring</tt>.
          </li>
          <li>
            The old key remains the signing key (<tt>signing</tt>
            true, <tt>status</tt> retiring) until an OPTIONAL
            <tt>switch_after</tt> (seconds) elapses, or until the
            server applies a local switch if <tt>switch_after</tt> is
            omitted or zero. After the switch the new key has
            <tt>signing</tt> true and the old key is
            <tt>retiring</tt> with <tt>signing</tt> false. The client
            MAY later <tt>DELETE</tt> the old key.
          </li>
        </ol>
        <sourcecode type="json">{
  "generate": { "kty": "EC", "crv": "P-256", "alg": "ES256" },
  "switch_after": 86400
}</sourcecode>
        <t>
          Response <tt>201</tt> with the new Key Document. The old key
          remains addressable at its original <tt>{kid}</tt>.
        </t>
      </section>
    </section>

    <section anchor="configuration">
      <name>Entity Configuration</name>
      <t>
        The Entity Configuration Admin Document is the
        operator-editable content of the node's self-signed Entity
        Statement. The server supplies <tt>iss</tt>, <tt>sub</tt>,
        <tt>iat</tt>, <tt>exp</tt>, and <tt>jwks</tt> when it signs.
        The operator supplies the remaining Entity Configuration
        claims.
      </t>

      <section>
        <name>Configuration Document</name>
        <sourcecode type="json">{
  "entity_id": "https://ta.example.org",
  "lifetime": 86400,
  "authority_hints": [],
  "metadata": {
    "federation_entity": {
      "organization_name": "Example Trust Anchor",
      "federation_fetch_endpoint": "https://ta.example.org/fetch",
      "federation_list_endpoint": "https://ta.example.org/list",
      "federation_trust_mark_status_endpoint":
        "https://ta.example.org/trust-mark-status"
    }
  },
  "trust_marks": [],
  "trust_mark_issuers": {
    "https://ta.example.org/marks/research": [
      "https://ta.example.org"
    ]
  },
  "trust_mark_owners": {}
}</sourcecode>
        <t>
          Members <tt>authority_hints</tt>,
          <tt>trust_anchor_hints</tt>, <tt>metadata</tt>,
          <tt>trust_marks</tt>, <tt>trust_mark_issuers</tt>,
          <tt>trust_mark_owners</tt>, and <tt>crit</tt> have the
          meanings and constraints of
          <xref target="OIDF.Federation"/>, Sections 3.1.1 and 3.1.2.
        </t>
        <t>
          <tt>trust_marks</tt> lists Trust Marks the node holds about
          itself. The server MUST copy these objects unchanged into
          the published Entity Configuration. It MUST NOT resign
          another issuer's Trust Mark.
        </t>
        <t>
          <tt>trust_mark_issuers</tt> and <tt>trust_mark_owners</tt>
          are meaningful only on a Trust Anchor. Servers MUST reject
          them on a node whose roles do not include
          <tt>trust_anchor</tt>.
        </t>
        <t>
          A Leaf or Intermediate MUST include a non-empty
          <tt>authority_hints</tt> array. A Trust Anchor with no
          Superior MUST omit <tt>authority_hints</tt> from the
          published Entity Configuration.
        </t>
      </section>

      <section>
        <name>GET {base}/configuration</name>
        <t>Returns the Configuration Document.</t>
      </section>
      <section>
        <name>PUT {base}/configuration</name>
        <t>
          Replaces the Configuration Document. Omitted optional
          members are cleared. Response <tt>200</tt>. The server MUST
          NOT allow <tt>entity_id</tt> to change after initialization
          (<xref target="bootstrap"/>). If <tt>entity_id</tt> is not
          yet set, this request MAY establish it.
        </t>
      </section>
      <section>
        <name>PATCH {base}/configuration</name>
        <t>Merge-patches the Configuration Document. Response <tt>200</tt>.</t>
      </section>
      <section>
        <name>GET {base}/configuration/statement</name>
        <t>
          Returns the currently published Entity Configuration JWT
          with <tt>Content-Type: application/entity-statement+jwt</tt>.
          This MUST be byte-for-byte the document served at
          <tt>/.well-known/openid-federation</tt>.
        </t>
      </section>
    </section>

    <section anchor="subordinates">
      <name>Subordinates</name>
      <t>
        The Subordinates resource is implemented by Trust Anchors and
        Intermediate Entities. Leaf nodes MUST return <tt>404</tt>
        with problem type <tt>unsupported_resource</tt> for every path
        under <tt>{base}/subordinates</tt>.
      </t>
      <t>
        A Subordinate Admin Document is the operator-editable content
        of the Subordinate Statement the node will sign about one
        Immediate Subordinate.
      </t>

      <section>
        <name>Subordinate Document</name>
        <sourcecode type="json">{
  "entity_id": "https://op.example.org",
  "status": "active",
  "lifetime": 86400,
  "jwks": {
    "keys": [
      {
        "kty": "EC",
        "crv": "P-256",
        "kid": "op-fed-1",
        "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
        "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"
      }
    ]
  },
  "metadata": {
    "openid_provider": { "organization_name": "Example University" }
  },
  "metadata_policy": {
    "openid_relying_party": {
      "id_token_signed_response_alg": {
        "default": "ES256",
        "one_of": ["ES256", "ES384", "ES512"]
      }
    }
  },
  "constraints": {
    "max_path_length": 1,
    "naming_constraints": { "permitted": [".example.org"] },
    "allowed_entity_types": [
      "openid_provider",
      "openid_relying_party"
    ]
  }
}</sourcecode>
        <t>
          <tt>jwks</tt> is REQUIRED for an <tt>active</tt> subordinate
          and is the subject's Federation Entity Keys. It MAY be
          omitted while <tt>status</tt> is <tt>pending</tt>. The
          server assigns <tt>iss</tt>, <tt>sub</tt>, <tt>iat</tt>,
          and <tt>exp</tt> when it signs. The server MAY add
          <tt>source_endpoint</tt> set to its
          <tt>federation_fetch_endpoint</tt>.
        </t>
      </section>

      <section>
        <name>GET {base}/subordinates</name>
        <t>
          Returns a page of Subordinate Documents. Default filter is
          <tt>status=active</tt>. Servers SHOULD omit <tt>jwks</tt>
          from list items unless the client passes
          <tt>detail=full</tt>.
        </t>
      </section>
      <section>
        <name>POST {base}/subordinates</name>
        <t>
          Creates a subordinate. <tt>entity_id</tt> is REQUIRED.
          Response <tt>201</tt>. If a non-revoked subordinate with
          the same <tt>entity_id</tt> exists, the server MUST return
          <tt>409</tt> with problem type <tt>already_exists</tt>.
          Live verification (<xref target="live-verify"/>) applies.
          To register a subject that is not yet online, set
          <tt>status</tt> to <tt>pending</tt>.
        </t>
      </section>
      <section>
        <name>GET, PUT, PATCH, DELETE {base}/subordinates/{entity_id}</name>
        <t>
          Read, replace, merge-patch, or revoke the Subordinate
          Document. <tt>PATCH</tt> is the compact replacement for the
          per-claim URLs used in <xref target="Sphereon.Admin"/> and
          <xref target="GEANT.Admin"/>. Replace and merge-patch
          follow <xref target="live-verify"/>.
        </t>
      </section>
      <section>
        <name>PUT {base}/subordinates/{entity_id}/status</name>
        <t>
          Sets <tt>status</tt> without a full document write. Body:
          <tt>{ "status": "suspended" }</tt>. The server MUST enforce
          <xref target="status"/>. A transition to <tt>active</tt>
          MUST live-verify (<xref target="live-verify"/>).
        </t>
      </section>
      <section>
        <name>GET {base}/subordinates/{entity_id}/statement</name>
        <t>
          Returns the currently published Subordinate Statement JWT.
          This MUST be byte-for-byte the document the node's
          <tt>federation_fetch_endpoint</tt> returns for that subject
          when status is <tt>active</tt>. Otherwise <tt>404</tt> with
          problem type <tt>not_published</tt>.
        </t>
      </section>
    </section>

    <section anchor="trust-marks">
      <name>Trust Marks</name>
      <t>
        The Trust Marks resource is implemented by Trust Mark Issuers.
        Other nodes MUST return <tt>404</tt> with problem type
        <tt>unsupported_resource</tt> for every path under
        <tt>{base}/trust-marks</tt>.
      </t>
      <t>
        This resource manages Trust Marks this node issues to
        subjects. Recognition claims
        (<tt>trust_mark_issuers</tt>, <tt>trust_mark_owners</tt>) and
        Trust Marks this node holds about itself
        (<tt>trust_marks</tt>) are Configuration Document members
        (<xref target="configuration"/>).
      </t>

      <section>
        <name>Issuance Document</name>
        <sourcecode type="json">{
  "trust_mark_type": "https://ta.example.org/marks/research",
  "lifetime": 31536000,
  "logo_uri": "https://ta.example.org/marks/research.png",
  "ref": "https://ta.example.org/marks/research/policy"
}</sourcecode>
        <t>
          <tt>trust_mark_type</tt> MUST be a collision-resistant
          identifier as specified in
          <xref target="OIDF.Federation"/>, Section 7.1.
          <tt>logo_uri</tt>, <tt>ref</tt>, and <tt>delegation</tt>
          (when present) are copied into issued Trust Marks.
        </t>
      </section>

      <section>
        <name>Subject Grant Document</name>
        <sourcecode type="json">{
  "entity_id": "https://op.example.org",
  "trust_mark_type": "https://ta.example.org/marks/research",
  "status": "active",
  "iat": 1756458000,
  "exp": 1787994000
}</sourcecode>
        <t>
          When <tt>status</tt> is <tt>active</tt>, the node MUST issue
          a Trust Mark JWT whose claims follow Section 7.1 of
          <xref target="OIDF.Federation"/>, typed
          <tt>trust-mark+jwt</tt>, and signed with a Federation
          Entity Key. When <tt>status</tt> is <tt>pending</tt>,
          <tt>suspended</tt>, or <tt>revoked</tt>,
          <tt>federation_trust_mark_status_endpoint</tt> MUST report
          the mark as inactive.
        </t>
      </section>

      <section>
        <name>Collection and Item Operations</name>
        <t>
          <tt>GET/POST {base}/trust-marks</tt> lists and creates
          Issuance Documents. <tt>GET/PUT/DELETE
          {base}/trust-marks/{type}</tt> reads, replaces, or revokes
          a type (revoking a type revokes every grant under it).
        </t>
        <t>
          <tt>GET {base}/trust-marks/{type}/subjects</tt> lists
          grants. <tt>PUT .../subjects/{entity_id}</tt> creates or
          replaces a grant. <tt>DELETE</tt> revokes it.
          <tt>PUT .../status</tt> sets grant status.
          <tt>GET .../token</tt> returns the issued JWT with
          <tt>Content-Type: application/trust-mark+jwt</tt> when the
          grant is <tt>active</tt>.
        </t>
        <t>
          Live verification (<xref target="live-verify"/>) applies to
          grant create, replace, and a status transition to
          <tt>active</tt>. To grant a mark to a subject that is not
          yet online, set <tt>status</tt> to <tt>pending</tt>.
        </t>
      </section>
    </section>

    <section anchor="errors">
      <name>Errors</name>
      <t>
        Error responses MUST use HTTP status codes consistently with
        <xref target="RFC9110"/> and a <xref target="RFC9457"/> body:
      </t>
      <sourcecode type="json">{
  "type":
    "urn:ietf:params:oidfed:admin:problem#invalid_federation_claim",
  "title": "Invalid federation claim",
  "status": 400,
  "detail": "authority_hints must not be empty on a leaf node",
  "pointer": "/authority_hints"
}</sourcecode>
      <t>
        <tt>pointer</tt> is an OPTIONAL JSON Pointer to the offending
        member.
      </t>
      <table anchor="tab-errors">
        <name>Problem tokens</name>
        <thead>
          <tr>
            <th>Token</th>
            <th>Status</th>
            <th>Meaning</th>
          </tr>
        </thead>
        <tbody>
          <tr><td><tt>invalid_request</tt></td><td>400</td><td>Malformed JSON or missing required member</td></tr>
          <tr><td><tt>invalid_federation_claim</tt></td><td>400</td><td>Claim violates <xref target="OIDF.Federation"/></td></tr>
          <tr><td><tt>unsupported_media_type</tt></td><td>415</td><td>Wrong Content-Type</td></tr>
          <tr><td><tt>unauthorized</tt></td><td>401</td><td>Missing or invalid authentication</td></tr>
          <tr><td><tt>forbidden</tt></td><td>403</td><td>Authenticated but not permitted</td></tr>
          <tr><td><tt>not_found</tt></td><td>404</td><td>Unknown resource or identifier</td></tr>
          <tr><td><tt>unsupported_resource</tt></td><td>404</td><td>Resource not implemented for this node role</td></tr>
          <tr><td><tt>not_published</tt></td><td>404</td><td>Configured but not currently published</td></tr>
          <tr><td><tt>already_exists</tt></td><td>409</td><td>Identifier already in use</td></tr>
          <tr><td><tt>last_signing_key</tt></td><td>409</td><td>Would remove the last usable signing key</td></tr>
          <tr><td><tt>not_initialized</tt></td><td>409</td><td>Entity Identifier or signing key not yet set</td></tr>
          <tr><td><tt>conflict</tt></td><td>409</td><td>Other conflicting state</td></tr>
          <tr><td><tt>precondition_failed</tt></td><td>412</td><td><tt>If-Match</tt> did not match</td></tr>
          <tr><td><tt>subject_mismatch</tt></td><td>422</td><td>Live verification failed or subject unreachable</td></tr>
          <tr><td><tt>internal</tt></td><td>500</td><td>Unspecified server failure</td></tr>
        </tbody>
      </table>
      <t>
        The <tt>type</tt> URI is formed by appending <tt>#</tt> and
        the token to <tt>urn:ietf:params:oidfed:admin:problem</tt>
        (<xref target="iana"/>).
      </t>
    </section>

    <section anchor="mapping">
      <name>Relationship to OpenID Federation 1.1</name>
      <t>
        This section is normative regarding consistency and
        informative regarding existing products. OpenID Federation
        1.1 <xref target="OIDF.Federation"/> is the
        protocol-independent split of OpenID Federation 1.0. It
        introduces no new federation mechanisms. OpenID Connect and
        OAuth metadata types used in examples
        (<tt>openid_provider</tt>, <tt>openid_relying_party</tt>)
        are defined in <xref target="OIDF.Connect"/>.
      </t>
      <table anchor="tab-mapping">
        <name>Admin resources and protocol artifacts</name>
        <thead>
          <tr>
            <th>Admin resource</th>
            <th>Protocol artifact</th>
            <th>OIDFed section</th>
          </tr>
        </thead>
        <tbody>
          <tr><td>Configuration</td><td>Entity Configuration JWT</td><td>3, 9</td></tr>
          <tr><td>Keys</td><td><tt>jwks</tt>; historical keys endpoint</td><td>3.1.1, 8.7, 11</td></tr>
          <tr><td>Subordinate</td><td>Subordinate Statement JWT from fetch</td><td>3, 8.1</td></tr>
          <tr><td>Subordinate list</td><td><tt>federation_list_endpoint</tt></td><td>8.2</td></tr>
          <tr><td>Trust Mark grant</td><td>Trust Mark JWT; status and list endpoints</td><td>7, 8.4–8.6</td></tr>
          <tr><td><tt>trust_mark_issuers</tt></td><td>Claim on Trust Anchor Entity Configuration</td><td>3.1.2, 7</td></tr>
          <tr><td><tt>metadata_policy</tt></td><td>Claim on Subordinate Statement</td><td>6.1</td></tr>
          <tr><td><tt>constraints</tt></td><td>Claim on Subordinate Statement</td><td>6.2</td></tr>
        </tbody>
      </table>
      <t>
        A node that implements this API MUST still implement the
        Protocol Plane required by its roles. Implementing this API
        does not satisfy any Protocol Plane requirement.
      </t>
      <t>
        <xref target="Sphereon.Admin"/>, <xref target="GEANT.Admin"/>,
        and the OpenAPI contract shipped with
        <xref target="Gateway.Admin"/> expose a large set of nested
        resources that map onto the documents in this specification:
        entity-configuration metadata, authority hints, and published
        JWKS collapse to <xref target="configuration"/> plus
        <xref target="keys"/>; per-subordinate metadata, policy,
        constraints, and JWKS collapse to
        <xref target="subordinates"/>; trust-mark types, issuance
        specs, and subjects collapse to
        <xref target="trust-marks"/>. Control-plane products such as
        <xref target="SURF.OIDFed"/> and
        <xref target="Gateway.Admin"/> sit above this API.
      </t>
    </section>

    <section anchor="deployment">
      <name>Deployment Considerations</name>
      <t>
        The Administration API and the Protocol Plane MAY share an
        origin or MAY use distinct origins. Distinct origins are
        RECOMMENDED so that operator credentials never appear on the
        host that federation participants contact.
      </t>
      <t>
        When origins differ, the Entity Identifier remains the
        Protocol Plane identifier. The Administration API base URL is
        local configuration. It MUST NOT be published in Entity
        Configuration metadata.
      </t>
      <t>
        A control plane that manages several nodes MUST address each
        Administration Server separately. This document does not
        define a multi-node collection resource.
      </t>
      <t>
        Servers SHOULD emit structured audit records for every
        mutating request, as specified in
        <xref target="security-audit"/>. This document does not
        define an Administration API resource for querying or
        managing those records.
      </t>
    </section>

    <section anchor="security">
      <name>Security Considerations</name>
      <t>
        The Administration API can change the trust fabric of a
        federation. Compromise of Administration API credentials is
        equivalent to compromise of the node's Federation Entity Keys
        for the purpose of issuing statements the rest of the
        federation will accept.
      </t>

      <section>
        <name>Authentication and Authorization</name>
        <t>
          Unauthenticated access MUST NOT be permitted. Bearer tokens
          MUST be sender-constrained or short-lived. Deployments
          SHOULD use mutual TLS or demonstration of proof-of-possession
          for operator credentials that can rotate keys or create
          subordinates. Separating "read configuration", "manage
          subordinates", "issue Trust Marks", and "rotate keys" is
          RECOMMENDED.
        </t>
      </section>
      <section>
        <name>Cross-Origin and Browser Clients</name>
        <t>
          If a browser-based operator interface is used, the
          Administration Server is a confidential backend-for-frontend
          concern. Browser clients MUST NOT be given long-lived
          node-admin credentials. Servers that offer CORS for a
          first-party UI MUST enumerate explicit origins and MUST NOT
          use <tt>*</tt>.
        </t>
      </section>
      <section>
        <name>Replay and Session Theft</name>
        <t>
          Bearer tokens that are not sender-constrained can be
          replayed until they expire. Servers MUST reject expired
          credentials. Clients SHOULD send <tt>If-Match</tt> on writes
          (<xref target="conventions"/>); a replayed <tt>PUT</tt> or
          <tt>PATCH</tt> whose <tt>If-Match</tt> no longer matches
          MUST fail with <tt>412</tt>.
        </t>
        <t>
          If a deployment authenticates operators with cookies or
          other automatically attached credentials, it MUST implement
          cross-site request forgery defenses (for example a
          synchronized token or a custom request header that is not
          sent cross-origin). This document specifies Bearer tokens.
          Cookie sessions are not required and are NOT RECOMMENDED
          for the Administration API.
        </t>
      </section>
      <section>
        <name>Injection into the Protocol Plane</name>
        <t>
          Every written claim is copied into a signed JWT that third
          parties will cache and apply as policy. Servers MUST treat
          Admin Document fields as untrusted input: reject unexpected
          types, reject <tt>null</tt> inside metadata objects
          (<xref target="OIDF.Federation"/>, Section 5), enforce URI
          syntax for Entity Identifiers and endpoints, and enforce
          <tt>https</tt> for federation endpoint URLs.
        </t>
      </section>
      <section>
        <name>Entity Identifier Spoofing</name>
        <t>
          A write that sets <tt>entity_id</tt> on a Subordinate
          Document or a Trust Mark grant is an assertion that the
          identified Entity is that subject. An Immediate Superior
          that publishes a Subordinate Statement binds the subject's
          Entity Identifier to the <tt>jwks</tt> in that document.
          Live verification (<xref target="live-verify"/>) MUST
          succeed before that binding is published.
          <tt>verify=false</tt> MUST NOT result in an
          <tt>active</tt> object. <tt>pending</tt> stores the
          document without publishing it.
        </t>
        <t>
          A successful live check only shows that the subject
          currently publishes matching <tt>jwks</tt> and
          <tt>authority_hints</tt>, or that a Trust Chain can be
          built. It is not a proof of organizational control.
          <tt>naming_constraints</tt> and
          <tt>allowed_entity_types</tt> MUST still be applied when
          present.
        </t>
      </section>
      <section>
        <name>Key Management</name>
        <t>
          Private keys MUST NOT be exported through this API. Key
          rollover MUST keep the retiring public key published long
          enough for relying parties to refresh Entity Configurations
          (<xref target="OIDF.Federation"/>, Section 11.2). Deleting
          the last signing key is rejected because it would freeze
          the Protocol Plane.
        </t>
      </section>
      <section>
        <name>Server-Side Request Forgery</name>
        <t>
          Live verification fetches a subject's Entity
          Configuration. Servers MUST apply SSRF controls:
          allow only <tt>https</tt>, deny private and link-local
          addresses unless explicitly configured, cap redirect hops,
          and cap response size.
        </t>
      </section>
      <section>
        <name>Availability</name>
        <t>
          Servers SHOULD rate-limit mutating requests,
          <tt>verify</tt> fetches, and expensive reads
          (<tt>detail=full</tt> and unfiltered lists). A client that
          can create subordinates or Trust Marks can otherwise exhaust
          storage and signing capacity. Unbounded list responses and
          repeated <tt>verify</tt> against slow or large Entity
          Configurations are denial-of-service vectors even for
          authenticated readers. Pagination
          (<xref target="conventions"/>) is not optional for large
          collections if the server cannot bound the result set.
        </t>
      </section>
      <section>
        <name>Residual Trust After Revoke</name>
        <t>
          OpenID Federation 1.1 does not define a revocation protocol
          (<xref target="OIDF.Federation"/>, Section 11.4). Setting
          <tt>status</tt> to <tt>suspended</tt> or <tt>revoked</tt>,
          or deleting a subordinate or Trust Mark grant, only stops
          this node from publishing the corresponding artifact.
          Relying parties continue to accept cached Entity Statements
          and Trust Marks until those artifacts expire or the relying
          party refreshes the Trust Chain. Operators MUST choose
          <tt>lifetime</tt> values that match how quickly the
          federation needs a withdrawal to take effect.
          <tt>DELETE</tt> is not instant global revocation.
        </t>
      </section>
      <section anchor="security-audit">
        <name>Audit and Non-Repudiation</name>
        <t>
          Administration actions SHOULD be attributable to an operator
          identity distinct from the node's Federation Entity
          Identifier. Audit logs are the primary record of who changed
          the trust fabric; Entity Statement <tt>iat</tt> values
          alone are not sufficient.
        </t>
        <t>
          This document does not define an audit-log resource. Query,
          retention, and export to a SIEM or other archive are
          deployment concerns, typically implemented by a control
          plane rather than by the node.
        </t>
        <t>
          A server SHOULD record at least the following for every
          mutating request:
        </t>
        <ul>
          <li>
            time of the request (seconds since the epoch, or an
            equivalent unambiguous timestamp);
          </li>
          <li>authenticated actor;</li>
          <li>
            operation name from <xref target="catalog"/> (for example
            <tt>subordinates.replace</tt>);
          </li>
          <li>
            target identifier (<tt>entity_id</tt>,
            <tt>trust_mark_type</tt>, or <tt>kid</tt>, as applicable);
          </li>
          <li>
            previous <tt>etag</tt> or a hash of the previous Admin
            Document;
          </li>
          <li>
            outcome (HTTP status, and problem token on failure).
          </li>
        </ul>
        <t>
          Privileged read operations MAY be recorded. Servers MUST NOT
          write private key material or access tokens into the audit
          trail. Request and response bodies MAY be stored in redacted
          form.
        </t>
        <t>
          The Administration API MUST NOT provide a means to delete or
          rewrite audit records. Retention period and archival policy
          are local matters.
        </t>
        <t>
          If a control plane proxies this API, the node still SHOULD
          emit its own records. When it does not, the operator MUST
          designate exactly one authoritative trail so that a change
          cannot occur without a durable attribution.
        </t>
      </section>
    </section>

    <section anchor="privacy">
      <name>Privacy Considerations</name>
      <t>
        The Administration API handles identifiers and metadata that
        often relate to organizations and, in audit logs, to
        individual operators. This section follows the guidance of
        <xref target="RFC6973"/>.
      </t>
      <t>
        Entity Identifiers, <tt>organization_name</tt>,
        <tt>logo_uri</tt>, and similar metadata members are published
        on the Protocol Plane once written. Operators MUST treat Admin
        Document writes as publication. Contact addresses and other
        optional metadata SHOULD be limited to what the federation
        policy requires.
      </t>
      <t>
        Trust Marks bind an accreditation statement to an Entity
        Identifier. Issuing or revoking a mark is visible to any party
        that can query the issuer's Trust Mark status endpoint.
      </t>
      <t>
        Audit records contain operator identities distinct from the
        node's Entity Identifier (<xref target="security-audit"/>).
        Those records MUST be access-controlled independently of the
        Protocol Plane and SHOULD NOT be written to the same log
        streams that serve public federation endpoints. Retention of
        operator identifiers is a local matter. Servers MUST NOT copy
        operator identities into Entity Statements or Trust Marks.
      </t>
      <t>
        Because the Administration API is confidential, responses MUST
        NOT be cached by shared caches. Distinct Administration and
        Protocol Plane origins (<xref target="deployment"/>) reduce
        the risk that a browser or intermediary mixes the two.
      </t>
    </section>

    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>
        This document makes no Well-Known URI registration. The
        Administration API is not discovered via
        <tt>/.well-known/openid-federation</tt>.
      </t>
      <t>
        IANA is requested to register the following value in the
        "IETF URN Sub-namespace for Registered Protocol Parameter
        Identifiers" registry established by
        <xref target="RFC3553"/>:
      </t>
      <ul>
        <li>URI: <tt>urn:ietf:params:oidfed:admin</tt></li>
        <li>Description: OpenID Federation Node Administration Protocol</li>
        <li>Reference: this document</li>
      </ul>
      <t>
        Problem-type tokens in <xref target="errors"/> are relative
        to <tt>urn:ietf:params:oidfed:admin:problem</tt>.
      </t>
    </section>
  </middle>

  <back>
    <references>
      <name>Normative References</name>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3553.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5789.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6749.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6750.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7396.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7515.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7517.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7519.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7638.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8259.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9110.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9457.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9525.xml"/>
      <reference anchor="OIDF.Federation" target="https://openid.net/specs/openid-federation-1_1.html">
        <front>
          <title>OpenID Federation 1.1</title>
          <author initials="R." surname="Hedberg" fullname="Roland Hedberg">
            <organization>independent</organization>
          </author>
          <author initials="M.B." surname="Jones" fullname="Michael B. Jones" role="editor">
            <organization>Self-Issued Consulting</organization>
          </author>
          <author initials="G." surname="De Marco" fullname="Giuseppe De Marco">
            <organization>independent</organization>
          </author>
          <author initials="A.Å." surname="Solberg" fullname="Andreas Åkre Solberg">
            <organization>Sikt</organization>
          </author>
          <author initials="J." surname="Bradley" fullname="John Bradley">
            <organization>Yubico</organization>
          </author>
          <author initials="V." surname="Dzhuvinov" fullname="Vladimir Dzhuvinov">
            <organization>Connect2id</organization>
          </author>
          <date year="2026" month="May" day="5"/>
        </front>
        <seriesInfo name="OpenID Foundation" value="Final"/>
      </reference>
    </references>
    <references>
      <name>Informative References</name>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6973.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9421.xml"/>
      <reference anchor="OIDF.Connect" target="https://openid.net/specs/openid-federation-connect-1_1.html">
        <front>
          <title>OpenID Federation for OpenID Connect 1.1</title>
          <author initials="R." surname="Hedberg" fullname="Roland Hedberg">
            <organization>independent</organization>
          </author>
          <author initials="M.B." surname="Jones" fullname="Michael B. Jones" role="editor">
            <organization>Self-Issued Consulting</organization>
          </author>
          <author initials="G." surname="De Marco" fullname="Giuseppe De Marco">
            <organization>independent</organization>
          </author>
          <author initials="A.Å." surname="Solberg" fullname="Andreas Åkre Solberg">
            <organization>Sikt</organization>
          </author>
          <author initials="J." surname="Bradley" fullname="John Bradley">
            <organization>Yubico</organization>
          </author>
          <author initials="V." surname="Dzhuvinov" fullname="Vladimir Dzhuvinov">
            <organization>Connect2id</organization>
          </author>
          <date year="2026" month="May" day="5"/>
        </front>
        <seriesInfo name="OpenID Foundation" value="Final"/>
      </reference>
      <reference anchor="Sphereon.Admin" target="https://app.swaggerhub.com/apis/4Sure/OpenIDFederationAdminServer/0.20.0-d41">
        <front>
          <title>OpenID Federation Admin Server API</title>
          <author>
            <organization>Sphereon</organization>
          </author>
          <date year="2025" month="April"/>
        </front>
      </reference>
      <reference anchor="GEANT.Admin" target="https://gitlab.software.geant.org/TI_Incubator/federation-admin-api">
        <front>
          <title>Federation Admin API</title>
          <author>
            <organization>GÉANT Trust and Identity Incubator</organization>
          </author>
          <date year="2025" month="July"/>
        </front>
      </reference>
      <reference anchor="Gateway.Admin" target="https://github.com/alexarlord-boop/federation-gateway">
        <front>
          <title>Federation Gateway</title>
          <author>
            <organization>Federation Gateway</organization>
          </author>
          <date year="2026"/>
        </front>
      </reference>
      <reference anchor="SURF.OIDFed" target="https://github.com/SURF-OpenID-Federation">
        <front>
          <title>SURF OpenID Federation</title>
          <author>
            <organization>SURF</organization>
          </author>
          <date year="2025"/>
        </front>
      </reference>
    </references>

    <section anchor="examples" numbered="false">
      <name>Complete Message Examples</name>
      <t>
        This appendix shows a Trust Anchor admitting an OpenID
        Provider and issuing a Trust Mark. Host names and keys are
        illustrative.
      </t>
      <section numbered="false">
        <name>Register a subordinate</name>
        <sourcecode type="http-message"><![CDATA[
POST /admin/v1/subordinates HTTP/1.1
Host: ta.example.org
Authorization: Bearer 6f3c...
Content-Type: application/json

{
  "entity_id": "https://op.example.org",
  "jwks": {
    "keys": [{
      "kty": "EC", "crv": "P-256", "kid": "op-fed-1",
      "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
      "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"
    }]
  },
  "metadata": {
    "openid_provider": {
      "organization_name": "Example University"
    }
  },
  "constraints": {
    "max_path_length": 0,
    "allowed_entity_types": ["openid_provider"]
  }
}
]]></sourcecode>
        <t>
          The server live-verifies the subject's Entity Configuration
          before publishing (<xref target="live-verify"/>). If the
          subject were not yet online, the body would include
          <tt>"status": "pending"</tt> and the Protocol Plane would
          not change.
        </t>
      </section>
      <section numbered="false">
        <name>Tighten policy with a merge patch</name>
        <sourcecode type="http-message"><![CDATA[
PATCH /admin/v1/subordinates/https%3A%2F%2Fop.example.org HTTP/1.1
Host: ta.example.org
Authorization: Bearer 6f3c...
Content-Type: application/merge-patch+json
If-Match: "s1"

{
  "metadata_policy": {
    "openid_provider": {
      "id_token_signing_alg_values_supported": {
        "subset_of": ["ES256", "ES384"]
      }
    }
  }
}
]]></sourcecode>
      </section>
    </section>

    <section anchor="catalog" numbered="false">
      <name>Operation Catalog</name>
      <t>
        The following operations are all of the protocol operations.
        Feature subsets are expressed only by omitting keys from
        <tt>capabilities</tt>. A Leaf implements the Node, Keys, and
        Configuration operations (ten). A Trust Anchor that also
        issues Trust Marks implements all twenty-eight. Paths in the
        catalog are relative to <tt>{base}</tt>.
      </t>
      <table anchor="tab-catalog">
        <name>Complete operation catalog</name>
        <thead>
          <tr>
            <th>Method</th>
            <th>Path</th>
            <th>Operation</th>
          </tr>
        </thead>
        <tbody>
          <tr><td>GET</td><td><tt>/</tt></td><td><tt>node.read</tt></td></tr>
          <tr><td>GET</td><td><tt>/keys</tt></td><td><tt>keys.list</tt></td></tr>
          <tr><td>POST</td><td><tt>/keys</tt></td><td><tt>keys.create</tt></td></tr>
          <tr><td>GET</td><td><tt>/keys/{kid}</tt></td><td><tt>keys.read</tt></td></tr>
          <tr><td>DELETE</td><td><tt>/keys/{kid}</tt></td><td><tt>keys.delete</tt></td></tr>
          <tr><td>POST</td><td><tt>/keys/{kid}/rotate</tt></td><td><tt>keys.rotate</tt></td></tr>
          <tr><td>GET</td><td><tt>/configuration</tt></td><td><tt>configuration.read</tt></td></tr>
          <tr><td>PUT</td><td><tt>/configuration</tt></td><td><tt>configuration.replace</tt></td></tr>
          <tr><td>PATCH</td><td><tt>/configuration</tt></td><td><tt>configuration.patch</tt></td></tr>
          <tr><td>GET</td><td><tt>/configuration/statement</tt></td><td><tt>configuration.statement</tt></td></tr>
          <tr><td>GET</td><td><tt>/subordinates</tt></td><td><tt>subordinates.list</tt></td></tr>
          <tr><td>POST</td><td><tt>/subordinates</tt></td><td><tt>subordinates.create</tt></td></tr>
          <tr><td>GET</td><td><tt>/subordinates/{entity_id}</tt></td><td><tt>subordinates.read</tt></td></tr>
          <tr><td>PUT</td><td><tt>/subordinates/{entity_id}</tt></td><td><tt>subordinates.replace</tt></td></tr>
          <tr><td>PATCH</td><td><tt>/subordinates/{entity_id}</tt></td><td><tt>subordinates.patch</tt></td></tr>
          <tr><td>DELETE</td><td><tt>/subordinates/{entity_id}</tt></td><td><tt>subordinates.delete</tt></td></tr>
          <tr><td>PUT</td><td><tt>/subordinates/{entity_id}/<br/>status</tt></td><td><tt>subordinates.status</tt></td></tr>
          <tr><td>GET</td><td><tt>/subordinates/{entity_id}/<br/>statement</tt></td><td><tt>subordinates.statement</tt></td></tr>
          <tr><td>GET</td><td><tt>/trust-marks</tt></td><td><tt>trust_marks.list</tt></td></tr>
          <tr><td>POST</td><td><tt>/trust-marks</tt></td><td><tt>trust_marks.create</tt></td></tr>
          <tr><td>GET</td><td><tt>/trust-marks/{type}</tt></td><td><tt>trust_marks.read</tt></td></tr>
          <tr><td>PUT</td><td><tt>/trust-marks/{type}</tt></td><td><tt>trust_marks.replace</tt></td></tr>
          <tr><td>DELETE</td><td><tt>/trust-marks/{type}</tt></td><td><tt>trust_marks.delete</tt></td></tr>
          <tr><td>GET</td><td><tt>/trust-marks/{type}/subjects</tt></td><td><tt>trust_marks.subjects.list</tt></td></tr>
          <tr><td>PUT</td><td><tt>/trust-marks/{type}/subjects/<br/>{entity_id}</tt></td><td><tt>trust_marks.grant</tt></td></tr>
          <tr><td>DELETE</td><td><tt>/trust-marks/{type}/subjects/<br/>{entity_id}</tt></td><td><tt>trust_marks.revoke</tt></td></tr>
          <tr><td>PUT</td><td><tt>/trust-marks/{type}/subjects/<br/>{entity_id}/status</tt></td><td><tt>trust_marks.status</tt></td></tr>
          <tr><td>GET</td><td><tt>/trust-marks/{type}/subjects/<br/>{entity_id}/token</tt></td><td><tt>trust_marks.token</tt></td></tr>
        </tbody>
      </table>
    </section>

    <section anchor="acks" numbered="false">
      <name>Acknowledgements</name>
      <t>
        This document draws operational experience from the Sphereon
        OpenID Federation Admin Server, the GÉANT Trust and Identity
        Incubator Federation Admin API, the Federation Gateway
        project, and the SURF OpenID Federation control plane and node
        implementations. The data model is that of OpenID Federation
        1.1; any elegance in this API comes from not inventing another
        one.
      </t>
    </section>

  </back>
</rfc>
