Skip to content

spec(core): require the AS to display and record client policy and terms links - #317

Draft
tnunamak wants to merge 4 commits into
mainfrom
spec/client-terms-myterms-0903
Draft

tnunamak wants to merge 4 commits into
mainfrom
spec/client-terms-myterms-0903

Conversation

@tnunamak

@tnunamak tnunamak commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

A grant is the durable record of consent, but it never had to say which privacy policy and terms the owner was shown before approving. If the owner later disputes what the client did with their data, neither side can establish which documents were on screen at approval. This adds the display and recording obligations in spec-core.md and corrects a prior-art entry in spec-deferred.md. Three obligations change, each at a different confidence.

Client terms links

policy_uri and tos_uri rise from MAY-display to SHOULD-display. RFC 7591 Section 2, which Core cites as the source of these two field names, already says the AS SHOULD display each URL when provided, so Core stated a weaker obligation than the vocabulary it reuses.

The AS MUST now record the exact displayed values in the grant's client.client_display, and MUST NOT record a resolved-but-undisplayed value as displayed. That way the grant captures the consent surface rather than the server's lookup. The text also bounds what the record is worth: a recorded URI establishes which documents the owner was pointed at, not what they said, because the target is under client control and can change after issuance. Retaining a snapshot or digest stays a SHOULD, citing ISO/IEC 29184:2020 §5.2.8 as the stronger bar, because fetching and storing third-party documents is a deployment cost and a new outbound-fetch surface rather than an authorization semantic.

Last, an ai_training request MUST have policy_uri in resolved metadata or the AS rejects it. Core already treats that purpose as the only one with protocol-level mandatory consent, and this attaches the policy link to it. No outside regime I found names AI training as a trigger for a heightened policy requirement, so this rests entirely on Core's own decision to single that purpose out. Push back here first.

MyTerms and the agreement standards

The deferred entry for this prior art named the wrong body and the wrong status: it is IEEE 7012-2025, published January 2026, not "ISO MyTerms".

No protocol field is added. An optional grant-level agreement object was considered and rejected: nothing publishes accepted terms today and no acceptance step exists, so the field would fix the shape of a record before the flow that produces it. Instead the entry records the two-sided design a future version should implement — the client publishes the rostered terms it accepts, the AS holds the term the owner chose, and the AS matches the two at grant time with no negotiation round trip.

The entry also rules out purpose_code as the route to a rostered term. An agreement URI is a syntactically valid purpose code, so that route is legal and still wrong: the ai_training rule switches on that field's value, and an agreement URI there defeats it.

Three citation rows are added, each explaining a rule Core now carries or naming a bar Core is measured against. ISO/IEC 29184 is why a recorded URI is weaker evidence than a retained version. ISO/IEC TS 27560 is named as a deferred export mapping. IEEE 7012 is why a PDPP grant records an authorization rather than an agreement.

Not verified

The reference implementation is untouched. packages/operator-ui/src/components/pdpp/consent-card.tsx renders neither link today, so the new SHOULD-display rule describes work that surface has not done, and this PR adds no conformance test for it.

Every standards citation here is second-hand, read through public previews and DPV's published mapping guide rather than the paywalled normative text, and each row is written to survive that. None makes a conformance claim: the TS 27560 row names four sections and defers the mapping rather than citing a clause, and the IEEE 7012 row states a relationship only.

pnpm spec:check and pnpm spec:dates pass on a rebase onto origin/main.

Assisted-by: AI

@vercel

vercel Bot commented Sep 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pdpp Ready Ready Preview Sep 10, 2026 10:15pm UTC

Request Review

@tnunamak
tnunamak force-pushed the spec/client-terms-myterms-0903 branch from 7d713df to 1d10f25 Compare September 3, 2026 22:16
@tnunamak tnunamak changed the title spec: display and record client terms and privacy links, and evaluate MyTerms (IEEE P7012) fit spec: display and record client terms links, and relate Core to the agreement standards Sep 3, 2026
Two entries in spec-deferred.md called this prior art "ISO MyTerms." It is
not an ISO standard. It is IEEE P7012, published in January 2026 as
IEEE 7012-2025, "Standard for Machine Readable Personal Privacy Terms."
Leaving the wrong name in a normative-adjacent document sends a reader
looking for a standard that does not exist, and it hid the fact that the
thing is now published rather than a draft we could ignore.

The deeper gap was that the entry said MyTerms "has not been evaluated for
fit," which left open whether PDPP was quietly drifting into an
incompatibility. This adds an informative entry that does the evaluation.

MyTerms inverts the usual direction of an online agreement: the individual
is the first party and offers privacy terms, and the service provider is
the second party that accepts one. The terms are not written per
relationship — they are picked from a roster kept by a neutral non-business
entity (today Customer Commons), where each term is a versioned
dereferenceable URL.

Against that model a PDPP grant is already the recorded agreement on the
owner's side: it is immutable, it names the second party, and it carries
the recipient-side commitments as structured fields (purpose_code,
retention, access_mode) rather than prose. The entry states the two places
the analogy breaks — MyTerms expects both sides to hold a record where PDPP
defines only the authorization server's copy, and MyTerms allows a
counter-offer where a PDPP grant is issued after consent rather than
negotiated — so a later reader does not overclaim the fit.

It also names the thing that would actually cause incompatibility:
inventing a PDPP-specific vocabulary for terms a roster already names. We
do not have that problem today, because purpose_code is an absolute URI the
authorization server must accept even when it does not recognize it, so a
rostered term is already expressible with no schema change. That is the
positive path, and keeping purpose_code open is what preserves it.

No Core change and no v0.1 commitment: the roster is small and the
second-party record format is unsettled, so this records the analysis and
the hedge rather than a dependency.

The same wrong name also appears twice in the 2026-08-20 working-session
notes. Those are left alone deliberately — they are a dated record of what
was said in the room, not a statement of fact about the standard.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
…s shown

An owner approving a PDPP grant may be shown the requesting application's
privacy policy and terms-of-service links, or may not be. Core left both
halves of that soft. It said the authorization server "MAY display them as
secondary links," and it never required the server to keep any trace of
which links it put in front of the owner. So an owner who later disputes
what a company was allowed to do with their data has no record of the terms
they were pointed at when they agreed, and the server has no way to show
one.

Two changes, and the first is smaller than it looks. RFC 7591 Section 2 —
the OAuth client-registration metadata vocabulary that Core already borrows
`policy_uri` and `tos_uri` from — says of each field that "the
authorization server SHOULD display this URL to the end-user if it is
provided." Core's MAY was therefore weaker than the source it cites, which
was a drafting slip rather than a decision. Raising it to SHOULD restores
the strength the borrowed vocabulary already carries.

The second change is a real addition: where the server displayed either
link, the issued grant MUST carry the exact displayed values in
`client.client_display`. This needs no new field. The grant schema already
has an optional `client_display` holding server-resolved requester identity
metadata, with `policy_uri` and `tos_uri` among its members — it was simply
never obligatory to populate them. The rule also says a value the server
resolved but did not show MUST NOT be recorded as displayed, so the record
stays a record of the consent surface rather than of the server's internal
lookup.

That evidence is deliberately bounded, and the text now says so rather than
overselling it. A recorded URI shows which documents the owner was pointed
at, not what those documents said, because the target belongs to the client
and can change after issuance. ISO/IEC 29184:2020 Section 5.2.8 — the ISO
standard on online privacy notices and consent — sets the stronger bar,
requiring that an organization "shall keep and make available the version
of the notice presented when the PII principal gave consent." Core points
deployments at that as a SHOULD instead of mandating it, because retaining
the version means fetching and storing third-party documents: a real
deployment cost and a new outbound-fetch surface, neither of which is an
authorization semantic.

Separately, a client requesting the `ai_training` purpose must now have a
`policy_uri` in its resolved metadata, and the server must reject the
request otherwise. Training on someone's personal data is already the one
purpose code where Core treats consent as protocol-enforced rather than
advisory, and consent to it is not informed if there is nowhere to read how
the recipient handles the data. The requirement is on the resolved
metadata, not on the inline request, so a client the server already knows
through registration or a validated binding does not have to resend it.

Confidence is uneven across the three and worth flagging for review. The
SHOULD-display realignment is near-certain — it is what the cited RFC says.
The recording obligation is well-precedented in the consent-receipt
lineage (ISO/IEC 29184, Kantara Consent Receipt) but has no precedent in
the OAuth or OpenID Connect family, so it is a genuine extension of that
lineage rather than a gap-fill. The `ai_training` policy_uri rule is the
weakest of the three: no regime found names AI training as a trigger for a
heightened privacy-policy requirement, so it rests on Core's own existing
decision to single that purpose out, not on outside prior art.

Verified: `pnpm spec:check`, which regenerates the site's spec pages from
these root files and fails on any drift between them, passes. `pnpm
spec:dates` fails only on spec-reference-implementation-examples.md, a file
this branch does not touch and which was already failing on origin/main.
No reference-implementation code changes here; the consent card in
packages/operator-ui renders neither link today, so the SHOULD-display rule
describes work that surface has not done yet.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
An independent judge reviewed the two stances on offer for terms support
and chose S1 over S2 (disagreeing with the research's own S2 recommendation
at 82/100 confidence). S2 would have added an optional `agreement` object to
the grant now. The judge's decisive reason: the argument for adding it early
rested on RFC 9396 Section 5, which constrains what a *client* may send in
an authorization request, while the proposed field was grant-side only. So
Section 5 neither forces nor eases that field, and adding it would
standardize a record shape before the flow that produces it exists — there
is no client publishing accepted terms, no publication surface, and no
acceptance step anywhere today.

This is S1: say precisely how PDPP relates to the standards in question, and
record the design a future version should implement, without inventing
fields for it now.

Section 1 gains four relationship rows. IEEE 7012-2025 (MyTerms) says a
PDPP grant records an authorization and could later reference an agreement;
it deliberately stops short of calling every grant an agreement record,
which would overstate what the grant is. W3C DPV 2.3 is named for its
consent-record vocabulary, and its extension for IEEE 7012 is described as
live — it ships in DPV 2.3 as `STANDARD-IEEE-7012`, which corrects an
earlier claim that the extension had been stranded at an old draft; the row
keeps the caveat that DPV is a Community Group report and not a W3C
standard. ISO/IEC TS 27560 is named as a deferred export mapping, and says
PDPP records a notice reference only where a link was actually displayed,
rather than claiming every grant carries 27560's mandatory notice field.
ISO/IEC 29184 is kept as written, because it is the citation that explains
why a recorded URI is weaker evidence than a retained version. ODRL was
proposed as a fifth row and is deliberately omitted: the mapping is
speculative and no v0.1 field depends on it. The UMA row gains one clause
noting that UMA puts the resource owner's policy outside its own scope,
which is why PDPP's structured commitments are an addition rather than a
divergence.

The deferred MyTerms entry drops the `purpose_code` route it previously
offered as the positive path, and now warns against it: an agreement URI is
a syntactically valid purpose code, so the route is legal and still wrong,
because purpose and agreement are separate objects everywhere and the
`ai_training` rule switches on the purpose code's value. In its place the
entry records the two-sided design a future version should implement. The
client publishes the rostered terms it accepts in its client metadata
document. The authorization server holds the rostered term the owner chose
from the IEEE 7012 roster. At grant time the server matches the two
mechanically, with no negotiation round trip. The grant records the matched
term — URI, version, acceptance time — in a future optional `agreement`
object that introspection echoes. PDPP defines no terms vocabulary of its
own, at this version or any later one; that is the thing that would create
incompatibility with a roster-based standard.

The entry also records why the request side is the half that needs a
version to land in: RFC 9396 Section 5 requires the authorization server to
reject an authorization details object of known type carrying unknown
fields, so a request-side carrier cannot be adopted incrementally by
clients and must be defined in the `https://pdpp.dev/data-access` type when
that version arrives. The grant-side and metadata-side halves carry no such
constraint.

The client `policy_uri`/`tos_uri` display-and-record change from the earlier
commits on this branch is unchanged.

Verified: `pnpm spec:check` passes; `pnpm spec:dates` passes (the unrelated
stale-date failure this branch reported earlier was fixed on main); and the
spec prose gate, which merged into main after the earlier commits here, now
reports no new findings against a merge-base baseline. That last one also
required rewriting four over-long sentences this branch had itself
introduced before the gate existed.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
Applying a weight test to the rows this branch added: a row in Section 1's
standards table earns its place only if it explains something the spec does
today, or names a bar the spec is measured against. A row that is merely
adjacent and interesting is table weight without a reader benefit. Four
rows went in; three survive that test.

ISO/IEC 29184 stays as written. It is the reason Core records what was
displayed rather than treating a bare URI as sufficient evidence, so it
explains a rule the spec already carries.

ISO/IEC TS 27560 stays as the deferred consent-record mapping, and now
absorbs what the separate DPV row was carrying. The Data Privacy Vocabulary
did not describe anything Core does today: it is the vocabulary such a
mapping would be expressed in, which makes it a detail of the 27560 row
rather than a relationship of its own. Naming it inside that row keeps the
useful part — DPV keeps purpose, consent, and the consent record as
distinct classes the way PDPP does, and its consent record points at a
notice object rather than a bare URL — and keeps the caveat that DPV is a
Community Group report and not a W3C standard. The separate row is dropped.

IEEE 7012 shrinks to the two short sentences that carry the load: the
individual proffers terms as the first party and both sides keep a matching
record, and a PDPP grant records an authorization rather than an agreement
and could later reference one. The conformance disclaimer and the
counter-offer detail move out of the table; the deferred entry in
spec-deferred.md already states both at length, and repeating them in a
one-line-per-cell table was duplication rather than emphasis. The row is
worth keeping at this size because the question it answers came out of
workshop feedback, so a reader arriving at the table will look for it.

ODRL is not added. It describes no current PDPP surface and the mapping to
it is speculative, so it fails the same test.

One consequential follow-on: the deferred entry's closing line listed the
four standards Section 1 relates to. It now lists three, because claiming a
DPV row that no longer exists would send a reader looking for it.

Verified: pnpm spec:check, pnpm spec:dates, and the spec prose gate against
a merge-base baseline all pass, the last reporting no new findings. Writing
the IEEE row as a single sentence tripped the gate's 25-word cap at 43
words, so it is two sentences.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
@tnunamak
tnunamak force-pushed the spec/client-terms-myterms-0903 branch from 07fd2de to 128d32e Compare September 10, 2026 22:12
@tnunamak tnunamak changed the title spec: display and record client terms links, and relate Core to the agreement standards spec(core): require the AS to display and record client policy and terms links Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant