Skip to content

Separate authentication and entitlements, add federated DRM#66

Draft
jdevalk wants to merge 6 commits into
mainfrom
feature/separate-auth-entitlements
Draft

Separate authentication and entitlements, add federated DRM#66
jdevalk wants to merge 6 commits into
mainfrom
feature/separate-auth-entitlements

Conversation

@jdevalk
Copy link
Copy Markdown
Member

@jdevalk jdevalk commented Mar 21, 2026

Summary

  • Separates auth (repository authentication) from entitlements (vendor-controlled access policy), resolving the conflation of authentication, authorization, and DRM in the existing auth property.
  • Adds FairEntitlementService as a new DID Document service type, giving vendors a trust anchor for entitlement verification that survives repository changes.
  • Defines an entitlement verification protocol with JWT-based entitlement proofs that can be validated by repositories, aggregators, and caches.
  • Writes the ext-auth.md extension defining bearer, basic, and oauth2 authentication methods (previously empty).
  • Adds entitlement types to the registry: subscription, purchase, license-key, free-registration.
  • Increases the description character limit from 140 to 250 characters (spec and JSON schema).

How it works

  1. Vendor registers a FairEntitlementService in their DID Document (trust anchor)
  2. Package metadata specifies entitlements with type, service URL, and user-facing hints
  3. Client validates the service URL matches the DID Document
  4. Client verifies the user's entitlement via POST to the vendor's service
  5. Vendor returns a signed JWT proof; client presents it to the repository as a bearer token
  6. Repository validates the JWT and serves the artifact

This means vendors control access regardless of which repository serves their package, and users keep their entitlements when packages move between repositories.

Files changed

  • specification.md — Core spec changes (auth narrowing, entitlements, DID service, verification protocol, flow diagrams, description limit)
  • schemas/metadata.schema.json — Updated description maxLength from 140 to 250
  • ext-auth.md — Authentication methods extension (bearer, basic, oauth2)
  • registry.md — Added entitlement types table
  • docs/implementing/restricted.md — Updated implementation guide
  • docs/restricted.md — Updated user-facing overview

Test plan

  • Review all cross-references between spec, extension, and registry for consistency
  • Walk through the installation flow for a free package (no entitlements) — should be unchanged
  • Walk through the installation flow for a restricted package with entitlements
  • Verify the DID Document example is valid
  • Verify backward compatibility: existing auth-only packages still work

🤖 Generated with Claude Code

The existing `auth` property on Release Documents conflated authentication
(how to present credentials) with authorization (whether a user may access
a package). This change separates the two concerns and adds a federated
entitlement verification protocol:

- Narrow `auth` on releases to repository authentication only
- Add `entitlements` property to Metadata Documents for vendor-controlled
  access policy (subscription, purchase, license-key, free-registration)
- Add `FairEntitlementService` DID Document service type as trust anchor
- Define entitlement verification protocol with JWT-based proofs
- Write the ext-auth.md authentication methods extension (bearer, basic, oauth2)
- Add entitlement types to the registry
- Update implementation guide and docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Joost de Valk <joost@altha.nl>
@jdevalk jdevalk force-pushed the feature/separate-auth-entitlements branch from 331484c to d456f05 Compare March 21, 2026 10:26
@jdevalk jdevalk marked this pull request as draft March 21, 2026 10:28
@toderash
Copy link
Copy Markdown
Member

The approach works for me. Background for other reviewers: TYPO3 hackathon discussion of how deeply FAIR should get into this - the concept has always existed, with placeholders in the spec. The approach needs to remain agnostic about the authentication method or platform, not requiring a specific type - e.g., maybe it's not based on a license key; actual implementation should also support an expiry date or next-reauth check so it doesn't have to be done on. every. single. page. load.

jdevalk and others added 3 commits March 21, 2026 13:10
- Change `provides` from empty array `[]` to empty object `{}` in both
  test data files (spec requires provides to be a map/object)
- Add a security contact to did_plc_m5tfrwxd3btacxlstcvop2ib.json
  (spec requires at least one security contact)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Joost de Valk <joost@altha.nl>
140 characters is too short for a meaningful package description.
250 characters allows 1-2 sentences while still keeping it concise.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Joost de Valk <joost@altha.nl>
Copy link
Copy Markdown
Member

@toderash toderash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flagged a few points to look at, but not comprehensive & didn't set a specific resolution, so simply accepting those won't really work.

The basic need is to define a means for the entitlement to expire & force reauthentication when needed - e.g., every 8 hours or 30 days or never or after a specific timestamp, now+365 days or an absolute UTC date/time or whatever, so if a subscription is renewed out of band, it'll simply re-auth and keep going, or do whatever's appropriate if the subscription expires.

{
"entitlements": {
"service": "https://licenses.example.com/verify",
"type": "subscription",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For type : subscription, should also add

"expires": <date/time as UTC>

| `purchase` | One-time purchase plugins/themes |
| `license-key` | Software with traditional license key activation |
| `free-registration` | Free plugins that require vendor registration |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider a require-reauth field, boolean false, after a time interval, or after a UTC timestamp

need a means of forcing a re-check for subscriptions, license expiry, or enforce reauth (oauth) as needed.


### 3. Set up repository authentication

On each release that has restricted artifacts, set `auth` to tell clients how to authenticate with the repository:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and when reauthentication must occur, if applicable.

```json
{
"auth": {
"type": "bearer",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"auth-expiry": "----",

jdevalk added 2 commits May 29, 2026 08:49
- Add require-reauth to entitlements object (vendor opt-in to disable proof caching)
- Document re-verification rules: cached proofs expire via exp, are discarded on repo 401, refresh on 403
- Remove the 24h cap on proof exp; expiry is at the entitlement service's discretion
- Document typical proof lifetimes per entitlement type in the registry
- Walk through expiry strategy in docs/implementing/restricted.md

Addresses toderash review on PR #66.
Resolve conflicts:
- Spec: keep entitlement-aware install flow, FairEntitlementService DID section, entitlements property, auth narrowed to repository auth
- Metadata table: merge main's last_updated/latest-security-release rows with this branch's entitlements row
- Description: keep 250-char limit from this branch
- Normalize Client/Repository/Package capitalization to main's convention
@jdevalk
Copy link
Copy Markdown
Member Author

jdevalk commented May 29, 2026

@toderash thanks for the review. I treated your inline comments as pointing at one underlying need — vendors must be able to control re-verification cadence, on any auth method, without forcing a check on every page load — rather than as four separate field requests, and the design landed slightly different from your suggestions. Walking through it so you can push back where I got it wrong:

1. The JWT proof's exp claim is now the authoritative re-verification deadline. It already existed but had a 24-hour cap; I removed the cap and replaced it with discretionary guidance + per-type examples. So a subscription proof can be valid for 30 days, a license-key proof can mirror the licence's own expiry (your "now+365 days" case), a high-security plugin can issue 8-hour proofs, and a free-registration can live for a year. The entitlement service picks the value at issuance — the metadata stays agnostic about auth method and entitlement model, which I think matches your March 21 note about not requiring a specific type.

This means clients are required to cache proofs until exp and refresh on 401/403 from the repository. They explicitly SHOULD NOT re-verify on every page load when a non-expired proof exists.

2. Added require-reauth: boolean on the entitlements object for the case where vendors do need to force a re-check on every protected action (per-seat enforcement, frequently-revoked entitlements). Default false. This is the bypass for "no caching, ever" — complementary to exp, not a replacement.

3. New "Caching and Re-verification" section in the spec spelling out exactly when a cached proof must be discarded:

  • exp reached (with clock-skew margin),
  • Repository or cache returns 401 Unauthorized while presenting the proof (treated as revocation),
  • Entitlement service returns 403 Forbidden on refresh.

If a refresh returns 401/402, clients prompt the user for new credentials.

4. Updated docs/implementing/restricted.md with a "When entitlements expire and how often clients re-check" walkthrough covering each entitlement type, plus a require-reauth: true example for the strict-enforcement case. This is what the four inline comments on lines 49/66/70/75 of the original review map to.

5. Registry: added a non-normative "Typical proof lifetime" column per entitlement type so vendors have somewhere to look when choosing an exp.

6. Schema: entitlements previously relied on additionalProperties: true. Now properly defined in metadata.schema.json with all six fields. npm test is green on both test fixtures.

Why not a metadata-level expires / auth-expiry field as you suggested? I worried that would split the source of truth — the JWT already carries an authoritative expiry that repositories and caches must check, so adding a parallel metadata field invites drift (metadata says 30 days, JWT says 1 hour, who wins?). Keeping exp on the proof as the single deadline and using require-reauth only as a binary cache-bypass felt cleaner. Happy to revisit if you'd rather have the field on metadata as well.

Also pulled in main and resolved the conflicts: integrated last_updated and latest-security-release into the metadata table alongside entitlements, kept the 250-char description limit, normalized Client/Repository/Package capitalization throughout.

Ready for another look when you have time.

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.

2 participants