From 3c0eb600a1dac4dc6dde9b961ef02ea696d66ec0 Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 13 Apr 2026 13:32:33 +0200 Subject: [PATCH 1/9] feat: add LWS Notifications subspecification Introduce a notifications subsystem for LWS with three channels: Server-Sent Events, WebSocket, and Webhooks. Key design decisions: - Single NotificationService with subscriptionType array - LWS-specific envelope wrapping Activity Streams 2.0 events - phase property (post-commit) for future admission controller extensibility - topic property for subscription targets (avoids items collision) - Webhook authentication via HTTP Message Signatures (RFC 9421) - inbox aligned with access-request-grant-proposal pattern Files: - lws10-notifications/index.html: New subspecification - lws10-core/Discovery.html: Updated NotificationService example - README.md: Added notifications to specs list --- README.md | 1 + lws10-core/Discovery.html | 3 +- lws10-notifications/index.html | 987 +++++++++++++++++++++++++++++++++ 3 files changed, 990 insertions(+), 1 deletion(-) create mode 100644 lws10-notifications/index.html diff --git a/README.md b/README.md index b162007..fbeb9ae 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ To see the most recent HTML rendered version of the specification from this repo - [`authn-saml`](lws10-authn-saml/): SAML 2.0 Authentication Suite - [`authn-ssi-cid`](lws10-authn-ssi-cid): Self-signed Controlled Identifier Authentication Suite - [`authn-ssi-did-key`](lws10-authn-ssi-did-key): Self-signed `did:key` Authentication Suite +- [`notifications`](lws10-notifications/): Notifications ## Contribution Guidelines: diff --git a/lws10-core/Discovery.html b/lws10-core/Discovery.html index 398c532..9b63bc0 100644 --- a/lws10-core/Discovery.html +++ b/lws10-core/Discovery.html @@ -125,7 +125,8 @@

Storage Description Representation

], "service": [{ "type": "NotificationService", - "serviceEndpoint": "https://storage.example/notification/api" + "serviceEndpoint": "https://storage.example/notification/api", + "subscriptionType": ["WebhookSubscription", "WebSocketSubscription", "EventSourceSubscription"] }, { "type": "TypeIndexService", "serviceEndpoint": "https://storage.example/types/api" diff --git a/lws10-notifications/index.html b/lws10-notifications/index.html new file mode 100644 index 0000000..b7bbf12 --- /dev/null +++ b/lws10-notifications/index.html @@ -0,0 +1,987 @@ + + + + + LWS Notifications + + + + +
+

+ This document extends the Linked Web Storage (LWS) protocol with a mechanism for clients + to receive timely updates about changes to resources. Three notification channels are + defined: Server-Sent Events, WebSocket, and Webhooks. All channels share a common + notification data model and are discoverable via the storage description resource. +

+
+
+

+ This is an unofficial proposal. +

+
+ +
+

Introduction

+ +

+ The [[!LWS-PROTOCOL|Linked Web Storage]] protocol defines a resource-centric storage + system built on HTTP. While the core protocol supports creating, reading, updating, and + deleting resources, it does not define a mechanism for clients to learn about changes + without polling. +

+ +

+ This specification extends LWS with a notification mechanism that allows clients + to subscribe to resource changes and receive updates through one of three channels: +

+ + + +

+ All three channels share a common notification envelope and are discoverable + via the storage description resource. +

+
+ +
+ +
+

Terminology

+ +

+ The terms "storage description resource", "resource manager", and "requesting agent" are + defined by [[!LWS-PROTOCOL]]. +

+ +

+ This specification defines the following additional terms: +

+ + +
+ +
+

Discovery

+ +

+ A client discovers notification support through the storage description resource. + A storage that supports notifications MUST advertise a service object in its + service array with type equal to + NotificationService. +

+ +

+ The service object MUST include a serviceEndpoint property whose value + is the URI of the subscription endpoint. The service object MUST include a + subscriptionType property whose value is an array of strings, each + identifying a supported subscription type. +

+ +

+ Additional properties MAY be present on the service object. +

+ +
+{
+  "@context": ["https://www.w3.org/ns/lws/v1"],
+  "id": "https://storage.example/",
+  "type": "Storage",
+  "service": [{
+    "type": "NotificationService",
+    "serviceEndpoint": "https://notification.example/subscriptions",
+    "subscriptionType": [
+      "WebhookSubscription",
+      "WebSocketSubscription",
+      "EventSourceSubscription"
+    ]
+  }]
+}
+      
+ +

+ A server is not required to support all subscription types. The + subscriptionType array advertises exactly which types are available. +

+
+ +
+

Notification Envelope

+ +

+ A notification is represented as a JSON-LD document with a + Notification type. The envelope carries metadata about the delivery + context and wraps an Activity Streams 2.0 [[ACTIVITYSTREAMS-CORE]] [[ACTIVITYSTREAMS-VOCABULARY]] + activity describing the event. +

+ +
+

Envelope Properties

+ +

+ A notification envelope has the following properties: +

+ +
    +
  • + type — REQUIRED. The value MUST be the string + Notification. +
  • +
  • + phase — REQUIRED. A string indicating the lifecycle phase + of the notification. The value MUST be post-commit. Other values + MAY be defined by future specifications. +
  • +
  • + storage — REQUIRED. A URI identifying the LWS storage with + which the notification is associated. +
  • +
  • + activity — REQUIRED. A JSON object or an array of JSON objects, + each conforming to the Activity Streams 2.0 data model, describing the event or + events that occurred. See . +
  • +
+ +
+{
+  "@context": [
+    "https://www.w3.org/ns/lws/v1",
+    "https://www.w3.org/ns/activitystreams"
+  ],
+  "type": "Notification",
+  "phase": "post-commit",
+  "storage": "https://storage.example/",
+  "activity": {
+    "id": "ec4dcc48-6581-4232-81c9-584525a98693",
+    "type": ["Delete"],
+    "object": {
+      "id": "https://storage.example/alice/notes/shopping.txt",
+      "type": "DataResource"
+    },
+    "origin": "https://storage.example/alice/notes/",
+    "published": "2026-03-26T10:30:00Z"
+  }
+}
+        
+
+ +
+

Activity Properties

+ +

+ The activity object MUST conform to the Activity Streams 2.0 data model + and MUST include the following properties: +

+ +
    +
  • + id — REQUIRED. A string uniquely identifying the activity. +
  • +
  • + type — REQUIRED. An array containing at least one Activity + Streams 2.0 activity type. +
  • +
  • + object — REQUIRED. A JSON object identifying the resource + that the notification is about. The object MUST include an id + property with the resource URI and a type property. +
  • +
  • + published — REQUIRED. A datetime value indicating when the + activity occurred. +
  • +
+ +

+ The following properties are OPTIONAL: +

+ +
    +
  • + actor — the agent that performed the action. +
  • +
  • + target — a URI identifying the container into which the + resource was added. Used with Create activities. +
  • +
  • + origin — a URI identifying the container from which the + resource was removed. Used with Delete activities. +
  • +
+
+ +
+

Activity Types

+ +

+ A server MUST support the following Activity Streams 2.0 activity types to + indicate LWS resource changes: +

+ +
    +
  • + Create — a new resource was created in a container. The + target field indicates the container to which the resource was added. +
  • +
  • + Update — an existing resource's content or metadata was modified. +
  • +
  • + Delete — a resource was removed. The origin field + indicates the container from which the resource was removed. +
  • +
+ +

+ Other activity types MAY also be supported. +

+
+ +
+

Batching Notifications

+ +

+ A server MAY combine multiple activities into a single notification envelope by + providing an array of activity objects as the value of the activity + property. +

+ +
+{
+  "@context": [
+    "https://www.w3.org/ns/lws/v1",
+    "https://www.w3.org/ns/activitystreams"
+  ],
+  "type": "Notification",
+  "phase": "post-commit",
+  "storage": "https://storage.example/",
+  "activity": [
+    {
+      "id": "a1b2c3d4-5678-9abc-def0-1234567890ab",
+      "type": ["Create"],
+      "object": {
+        "id": "https://storage.example/alice/notes/meeting.txt",
+        "type": "DataResource"
+      },
+      "target": "https://storage.example/alice/notes/",
+      "published": "2026-03-26T10:30:00Z"
+    },
+    {
+      "id": "b2c3d4e5-6789-abcd-ef01-234567890abc",
+      "type": ["Update"],
+      "object": {
+        "id": "https://storage.example/alice/profile",
+        "type": "DataResource"
+      },
+      "published": "2026-03-26T10:30:01Z"
+    }
+  ]
+}
+        
+
+
+ +
+

Subscriptions

+ +

+ To receive notifications, a client creates a subscription by sending an + authenticated POST request to the serviceEndpoint of the + NotificationService. The request body MUST conform to the + application/lws+json media type. +

+ +
+

Subscription Request

+ +

+ A subscription request MUST contain the following fields: +

+ +
    +
  • + type — REQUIRED. A string identifying the subscription type. + The value MUST be one of the types listed in the subscriptionType + array of the NotificationService. +
  • +
  • + phase — REQUIRED. A string indicating the lifecycle phase for + which notifications are requested. The value MUST be post-commit. + Other values MAY be defined by future specifications. +
  • +
  • + topic — REQUIRED. An array of URIs identifying the resources + included in the subscription. A subscription to a container includes notifications + for all resources contained in that container. +
  • +
+ +

+ A subscription request MAY contain additional fields as required by the specific + subscription type. +

+ +
+POST /subscriptions HTTP/2
+Host: notification.example
+Authorization: Bearer <access-token>
+Content-Type: application/lws+json
+
+{
+  "@context": ["https://www.w3.org/ns/lws/v1"],
+  "type": "EventSourceSubscription",
+  "phase": "post-commit",
+  "topic": [
+    "https://storage.example/alice/notes/",
+    "https://storage.example/alice/profile"
+  ]
+}
+        
+ +

+ A server MUST enforce resource authorization. If an agent does not have the + equivalent of read access to all listed resources, a server MUST reject the + subscription request. +

+
+ +
+

Subscription Response

+ +

+ The response to a successful subscription creation request MUST conform to the + application/lws+json media type and MUST contain the following fields: +

+ +
    +
  • + type — REQUIRED. A string equal to the subscription type from + the request. +
  • +
  • + subscription — REQUIRED. A URL representing the subscription. +
  • +
+
+
+ +
+

WebSocket Notifications

+ +

+ The WebSocket notification channel allows a client to receive notifications over a + persistent WebSocket connection. +

+ +
+

Creating a WebSocket Subscription

+ +

+ When a client creates a WebSocket notification subscription, the subscription body + MUST include a type field equal to WebSocketSubscription. +

+ +

+ A successful response body has these additional requirements: +

+ +
    +
  • + type — the value of this property MUST be a string equal to + WebSocketSubscription. +
  • +
  • + subscription — the value of this property MUST be a + capability URL that can be used by the WebSocket API. +
  • +
+ +
+{
+  "@context": ["https://www.w3.org/ns/lws/v1"],
+  "type": "WebSocketSubscription",
+  "subscription": "wss://notification.example/ws/1c2d3e4f5a6b"
+}
+        
+
+ +
+

Establishing a WebSocket Connection

+ +

+ After obtaining a capability URL, the client opens a WebSocket connection to + that URL. The server sends notification envelopes as WebSocket text messages, serialized + as JSON. +

+ +
+const ws = new WebSocket(capabilityUrl);
+ws.onmessage = (event) => {
+  const notification = JSON.parse(event.data);
+  // handle notification
+};
+        
+ +

+ The lifecycle of a WebSocket subscription is tied to the connection. When the + WebSocket connection is closed, the subscription is terminated. +

+
+
+ +
+

Server-Sent Event Notifications

+ +

+ The Server-Sent Event (SSE) notification channel allows a client to receive + notifications over a persistent HTTP connection using the EventSource API. +

+ +
+

Creating an EventSource Subscription

+ +

+ When a client creates an EventSource notification subscription, the subscription body + MUST include a type field equal to EventSourceSubscription. +

+ +

+ A successful response body has these additional requirements: +

+ +
    +
  • + type — the value of this property MUST be a string equal to + EventSourceSubscription. +
  • +
  • + subscription — the value of this property MUST be a + capability URL that can be used by the EventSource API. +
  • +
+ +
+{
+  "@context": ["https://www.w3.org/ns/lws/v1"],
+  "type": "EventSourceSubscription",
+  "subscription": "https://notification.example/sse/0d8b4c2e1a3f"
+}
+        
+
+ +
+

Establishing an EventSource Connection

+ +

+ After obtaining a capability URL, the client establishes a persistent SSE + connection to that URL. The server responds with Content-Type: + text/event-stream and pushes notification envelopes as events. Each event + MUST include an id field to support reconnection via the + Last-Event-ID header. +

+ +
+const source = new EventSource(capabilityUrl);
+source.onmessage = (event) => {
+  const notification = JSON.parse(event.data);
+  // handle notification
+};
+        
+ +

+ The lifecycle of an EventSource subscription is tied to the connection. When + the connection is closed, the subscription is terminated. +

+
+
+ +
+

Webhook Notifications

+ +

+ Webhooks enable server-to-server notification delivery. After a webhook subscription is + created, the LWS storage server delivers notifications to the registered + webhook endpoint when relevant changes occur. +

+ +
+

Creating a Webhook Subscription

+ +

+ When a client creates a webhook notification subscription, the subscription body MUST + include a type field equal to WebhookSubscription. In + addition, a server MUST support the following fields: +

+ +
    +
  • + inbox — REQUIRED. The URI of the endpoint to which notification + messages are sent. +
  • +
  • + expires — OPTIONAL. A datetime value indicating when the + subscription expires. +
  • +
+ +
+POST /subscriptions HTTP/2
+Host: notification.example
+Authorization: Bearer <access-token>
+Content-Type: application/lws+json
+
+{
+  "@context": ["https://www.w3.org/ns/lws/v1"],
+  "type": "WebhookSubscription",
+  "phase": "post-commit",
+  "topic": [
+    "https://storage.example/alice/notes/",
+    "https://storage.example/alice/profile"
+  ],
+  "inbox": "https://receiver.example/hooks/lws",
+  "expires": "2026-06-09T12:00:00Z"
+}
+        
+ +

+ A successful response body has these additional requirements: +

+ +
    +
  • + type — the value of this property MUST be a string equal to + WebhookSubscription. +
  • +
  • + subscription — a URL that can be used to manage the lifecycle of + the subscription. +
  • +
  • + expires — OPTIONAL. A datetime value indicating when the + subscription expires. +
  • +
+ +
+HTTP/2 200 OK
+Content-Type: application/lws+json
+Location: https://notification.example/subscriptions/9e8d7c6b5a4f
+
+{
+  "@context": ["https://www.w3.org/ns/lws/v1"],
+  "type": "WebhookSubscription",
+  "subscription": "https://notification.example/subscriptions/9e8d7c6b5a4f",
+  "expires": "2026-06-09T12:00:00Z"
+}
+        
+
+ +
+

Webhook Authentication

+ +

+ When a server delivers a notification to a webhook endpoint, the receiving + party needs to verify that the request is authentic. +

+ +

+ A server SHOULD sign each outbound request using HTTP Message Signatures + [[!RFC9421]]. When a webhook endpoint receives a signed message, it MUST verify + the signature using the notification server's public key, discoverable via the storage + description resource. +

+ +

+ A server that supports HTTP Message Signatures MUST include the public portion of + its signing key in the storage description resource using a + verificationMethod property. +

+ +
+{
+  "@context": ["https://www.w3.org/ns/lws/v1"],
+  "id": "https://storage.example/",
+  "type": "Storage",
+  "verificationMethod": [{
+    "id": "https://storage.example/#key-20260320",
+    "type": "JsonWebKey",
+    "controller": "https://storage.example/",
+    "publicKeyJwk": {
+      "kid": "key-20260320",
+      "kty": "EC",
+      "crv": "P-256",
+      "alg": "ES256",
+      "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
+      "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"
+    }
+  }],
+  "service": [{
+    "type": "NotificationService",
+    "serviceEndpoint": "https://notification.example/subscriptions",
+    "subscriptionType": ["WebhookSubscription"]
+  }]
+}
+        
+ +
+

Signature Requirements

+ +

+ A server that signs webhook delivery requests MUST include at least the following + components in the signature base: +

+ +
    +
  • @method — the HTTP method of the request (always POST).
  • +
  • @scheme — prevents downgrade from https to http.
  • +
  • + @authority — the host of the webhook endpoint, + preventing delivery to an unintended endpoint. +
  • +
  • + @path — the path component of the webhook endpoint URL. +
  • +
  • + content-type — the media type of the request body. +
  • +
  • + content-digest — a digest of the request body, computed + according to [[!RFC9530]]. +
  • +
+ +

+ The Signature-Input field MUST include the created and + keyid parameters. The keyid value MUST correspond to + the id of a key in the verificationMethod array of the + storage description resource. +

+
+ +
+

Signature Verification

+ +

+ To verify a webhook signature, a receiver MUST perform the following steps: +

+ +
    +
  1. + Extract the keyid value from the Signature-Input + field. The keyid value MUST be a URL with a fragment component. +
  2. +
  3. + Remove the fragment component from the keyid URL. The resulting + URL is the storage identifier. +
  4. +
  5. + Dereference the storage identifier to retrieve the storage description resource. + The id property of the top-level document map MUST match the + storage identifier. +
  6. +
  7. + Find the object in the verificationMethod array whose + id property matches either the full keyid URL or the + fragment component of the keyid URL. +
  8. +
  9. + Verify the HTTP Message Signature using the located verification method. +
  10. +
+
+
+ +
+

Subscription Management

+ +

+ The value of the serviceEndpoint property for a + NotificationService that supports WebhookSubscription + MUST be a URL that supports GET operations to list an agent's active + webhook subscriptions. The resulting serialization MUST conform to the requirements + for LWS Containers [[!LWS-PROTOCOL]]. The response SHOULD support LWS Paging. +

+ +

+ Each subscription resource listed in this container MUST support GET + and DELETE operations. A GET request returns the current + state of the subscription. A DELETE request cancels the subscription. +

+
+ +
+

Notification Delivery

+ +

+ The server sends an HTTP POST request to the registered + webhook endpoint with the notification envelope as the request body. The + request body MUST conform to the application/lws+json media type. +

+ +
    +
  • + Acknowledgment: A 2xx response indicates successful receipt. +
  • +
  • + Retry: On failure, the server MAY retry delivery. +
  • +
  • + Expiration: After repeated failures, the server MAY deactivate + the subscription. +
  • +
+
+
+ +
+

Security Considerations

+ + +
+ +
+

Privacy Considerations

+ + +
+ +
+

Vocabulary

+ +

+ This document defines the following terms in the + https://www.w3.org/ns/lws# namespace: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TermURIDescription
Notificationlws:NotificationNotification envelope type
NotificationServicelws:NotificationServiceService type for notification discovery
WebSocketSubscriptionlws:WebSocketSubscriptionWebSocket subscription type
EventSourceSubscriptionlws:EventSourceSubscriptionServer-Sent Event subscription type
WebhookSubscriptionlws:WebhookSubscriptionWebhook subscription type
subscriptionTypelws:subscriptionTypeSupported subscription types on a notification service
subscriptionlws:subscriptionURL of the subscription resource
phaselws:phaseLifecycle phase of the notification
activitylws:activityActivity Streams 2.0 payload within a notification
topiclws:topicArray of resource URIs included in a subscription
storagelws:storageURI identifying the LWS storage
+ +

+ This document uses the following terms from external vocabularies, which should be + added to the LWS JSON-LD context: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TermURISource
verificationMethodhttps://w3id.org/security#verificationMethodSecurity Vocabulary
controllerhttps://w3id.org/security#controllerSecurity Vocabulary
publicKeyJwkhttps://w3id.org/security#publicKeyJwkSecurity Vocabulary
inboxhttp://www.w3.org/ns/ldp#inboxLinked Data Platform
expireshttps://schema.org/expiresSchema.org
+
+ + From 0458acaadc9de62bb2eb30b3802c069ca1be7031 Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 13 Apr 2026 13:56:52 +0200 Subject: [PATCH 2/9] fix: improve notifications spec based on review - Clarify MAY support / MUST advertise pattern for notifications - Make phase OPTIONAL, use PascalCase (PostCommit) - Remove forward references to future specifications - Add Subscriber to terminology, use consistently throughout - Add Subscription Scope section (recursive container subscriptions) - Add Subscription Authorization section (delivery-time authz, subcontainer filtering, authorization change handling) - Tighten object structure normatively (nested id/type requirements) - Add authentication verification relationship per CID 1.0 - Add Activity Streams 2.0 terms to vocabulary table - Add PostCommit as vocabulary term - Source external terms from CID-1.0 instead of generic Security Vocab --- lws10-notifications/index.html | 265 ++++++++++++++++++++++++--------- 1 file changed, 192 insertions(+), 73 deletions(-) diff --git a/lws10-notifications/index.html b/lws10-notifications/index.html index b7bbf12..2345b4f 100644 --- a/lws10-notifications/index.html +++ b/lws10-notifications/index.html @@ -41,6 +41,12 @@ publisher: "IETF", status: "Proposed Standard", }, + "CID-1.0": { + title: "Controlled Identifiers 1.0", + href: "https://www.w3.org/TR/cid-1.0/", + publisher: "W3C", + status: "REC", + }, }, }; @@ -102,8 +108,13 @@

Introduction

Terminology

- The terms "storage description resource", "resource manager", and "requesting agent" are - defined by [[!LWS-PROTOCOL]]. + The terms "storage description resource", "resource manager", "requesting agent", + "container", and "data resource" are defined by [[!LWS-PROTOCOL]]. +

+ +

+ The terms "controlled identifier document", "verification method", and "verification + relationship" are defined by Controlled Identifiers 1.0 [[!CID-1.0]].

@@ -119,12 +130,16 @@

Terminology

Subscription — a registration expressing interest in receiving notifications for a given resource or set of resources. +
  • + Subscriber — the agent that creates a subscription and + receives the resulting notifications. +
  • Capability URL — a URL that encodes a subscription scope and serves as the credential for establishing a notification connection.
  • - Webhook Endpoint — a URL controlled by a subscribing party to + Webhook Endpoint — a URL controlled by a subscriber to which the server delivers notifications via HTTP.
  • @@ -134,10 +149,9 @@

    Terminology

    Discovery

    - A client discovers notification support through the storage description resource. - A storage that supports notifications MUST advertise a service object in its - service array with type equal to - NotificationService. + A storage MAY support notifications. A storage that supports notifications MUST + advertise a service object in the service array of its storage description + resource with type equal to NotificationService.

    @@ -197,9 +211,9 @@

    Envelope Properties

    Notification.
  • - phase — REQUIRED. A string indicating the lifecycle phase - of the notification. The value MUST be post-commit. Other values - MAY be defined by future specifications. + phase — OPTIONAL. A string indicating the lifecycle phase + of the notification. This specification defines the value + PostCommit.
  • storage — REQUIRED. A URI identifying the LWS storage with @@ -219,14 +233,14 @@

    Envelope Properties

    "https://www.w3.org/ns/activitystreams" ], "type": "Notification", - "phase": "post-commit", + "phase": "PostCommit", "storage": "https://storage.example/", "activity": { "id": "ec4dcc48-6581-4232-81c9-584525a98693", "type": ["Delete"], "object": { "id": "https://storage.example/alice/notes/shopping.txt", - "type": "DataResource" + "type": ["DataResource"] }, "origin": "https://storage.example/alice/notes/", "published": "2026-03-26T10:30:00Z" @@ -239,8 +253,8 @@

    Envelope Properties

    Activity Properties

    - The activity object MUST conform to the Activity Streams 2.0 data model - and MUST include the following properties: + Each activity object within the activity property MUST conform to the + Activity Streams 2.0 data model and MUST include the following properties:

      @@ -248,17 +262,28 @@

      Activity Properties

      id — REQUIRED. A string uniquely identifying the activity.
    • - type — REQUIRED. An array containing at least one Activity - Streams 2.0 activity type. + type — REQUIRED. An array of strings containing at least one + Activity Streams 2.0 activity type.
    • object — REQUIRED. A JSON object identifying the resource - that the notification is about. The object MUST include an id - property with the resource URI and a type property. + that the notification is about. The object MUST include the + following properties: +
        +
      • + id — REQUIRED. The URI of the resource. +
      • +
      • + type — REQUIRED. An array of strings containing at least + one resource type. Values defined by [[!LWS-PROTOCOL]] include + Container and DataResource. Additional type values + MAY be included. +
      • +
    • - published — REQUIRED. A datetime value indicating when the - activity occurred. + published — REQUIRED. A datetime value conforming to + [[!RFC3339]] indicating when the activity occurred.
    @@ -268,7 +293,7 @@

    Activity Properties

    • - actor — the agent that performed the action. + actor — a URI identifying the agent that performed the action.
    • target — a URI identifying the container into which the @@ -324,7 +349,7 @@

      Batching Notifications

      "https://www.w3.org/ns/activitystreams" ], "type": "Notification", - "phase": "post-commit", + "phase": "PostCommit", "storage": "https://storage.example/", "activity": [ { @@ -332,7 +357,7 @@

      Batching Notifications

      "type": ["Create"], "object": { "id": "https://storage.example/alice/notes/meeting.txt", - "type": "DataResource" + "type": ["DataResource"] }, "target": "https://storage.example/alice/notes/", "published": "2026-03-26T10:30:00Z" @@ -342,7 +367,7 @@

      Batching Notifications

      "type": ["Update"], "object": { "id": "https://storage.example/alice/profile", - "type": "DataResource" + "type": ["DataResource"] }, "published": "2026-03-26T10:30:01Z" } @@ -356,8 +381,8 @@

      Batching Notifications

      Subscriptions

      - To receive notifications, a client creates a subscription by sending an - authenticated POST request to the serviceEndpoint of the + To receive notifications, a subscriber creates a subscription by sending + an authenticated POST request to the serviceEndpoint of the NotificationService. The request body MUST conform to the application/lws+json media type.

      @@ -376,14 +401,20 @@

      Subscription Request

      array of the NotificationService.
    • - phase — REQUIRED. A string indicating the lifecycle phase for - which notifications are requested. The value MUST be post-commit. - Other values MAY be defined by future specifications. + topic — REQUIRED. An array of URIs identifying the resources + included in the subscription.
    • +
    + +

    + A subscription request MAY contain the following fields: +

    + +
    • - topic — REQUIRED. An array of URIs identifying the resources - included in the subscription. A subscription to a container includes notifications - for all resources contained in that container. + phase — OPTIONAL. A string indicating the lifecycle phase for + which notifications are requested. This specification defines the value + PostCommit.
    @@ -401,18 +432,57 @@

    Subscription Request

    { "@context": ["https://www.w3.org/ns/lws/v1"], "type": "EventSourceSubscription", - "phase": "post-commit", + "phase": "PostCommit", "topic": [ "https://storage.example/alice/notes/", "https://storage.example/alice/profile" ] } + + +
    +

    Subscription Scope

    + +

    + A subscription to a container is recursive: the subscriber receives + notifications for the container itself and for all resources transitively contained + in that container. A subscription to a data resource applies only to that + individual resource. +

    +
    + +
    +

    Subscription Authorization

    + +

    + A server MUST enforce resource authorization when creating a subscription. + If a subscriber does not have the equivalent of read access to all resources + listed in the topic array, the server MUST reject the subscription + request. +

    + +

    + Authorization MUST also be enforced at notification delivery time. A server MUST + NOT deliver a notification about a resource that the subscriber is + not authorized to read at the time the event occurs. This applies to all resources + within the scope of a subscription, including resources in subcontainers. +

    - A server MUST enforce resource authorization. If an agent does not have the - equivalent of read access to all listed resources, a server MUST reject the - subscription request. + If the subscriber's access to a resource or container within the scope of a + subscription is revoked after the subscription is created, the server + MUST stop delivering notifications for the affected resources. The server SHOULD + NOT terminate the entire subscription unless the subscriber has lost + access to all resources in the topic array. +

    + +

    + Subscription-time authorization verifies that a subscriber has a legitimate + basis for receiving notifications. Delivery-time authorization ensures that + notifications remain consistent with the subscriber's current permissions, + accounting for authorization changes that may occur after the subscription + was created.

    @@ -440,8 +510,8 @@

    Subscription Response

    WebSocket Notifications

    - The WebSocket notification channel allows a client to receive notifications over a - persistent WebSocket connection. + The WebSocket notification channel allows a subscriber to receive notifications + over a persistent WebSocket connection.

    @@ -480,9 +550,9 @@

    Creating a WebSocket Subscription

    Establishing a WebSocket Connection

    - After obtaining a capability URL, the client opens a WebSocket connection to - that URL. The server sends notification envelopes as WebSocket text messages, serialized - as JSON. + After obtaining a capability URL, the subscriber opens a WebSocket + connection to that URL. The server sends notification envelopes as WebSocket text + messages, serialized as JSON.

    @@ -504,7 +574,7 @@ 

    Establishing a WebSocket Connection

    Server-Sent Event Notifications

    - The Server-Sent Event (SSE) notification channel allows a client to receive + The Server-Sent Event (SSE) notification channel allows a subscriber to receive notifications over a persistent HTTP connection using the EventSource API.

    @@ -544,8 +614,8 @@

    Creating an EventSource Subscription

    Establishing an EventSource Connection

    - After obtaining a capability URL, the client establishes a persistent SSE - connection to that URL. The server responds with Content-Type: + After obtaining a capability URL, the subscriber establishes a + persistent SSE connection to that URL. The server responds with Content-Type: text/event-stream and pushes notification envelopes as events. Each event MUST include an id field to support reconnection via the Last-Event-ID header. @@ -572,7 +642,7 @@

    Webhook Notifications

    Webhooks enable server-to-server notification delivery. After a webhook subscription is created, the LWS storage server delivers notifications to the registered - webhook endpoint when relevant changes occur. + webhook endpoint of the subscriber when relevant changes occur.

    @@ -604,7 +674,7 @@

    Creating a Webhook Subscription

    { "@context": ["https://www.w3.org/ns/lws/v1"], "type": "WebhookSubscription", - "phase": "post-commit", + "phase": "PostCommit", "topic": [ "https://storage.example/alice/notes/", "https://storage.example/alice/profile" @@ -651,24 +721,26 @@

    Creating a Webhook Subscription

    Webhook Authentication

    - When a server delivers a notification to a webhook endpoint, the receiving - party needs to verify that the request is authentic. + When a server delivers a notification to a webhook endpoint, the + subscriber needs to verify that the request is authentic.

    A server SHOULD sign each outbound request using HTTP Message Signatures - [[!RFC9421]]. When a webhook endpoint receives a signed message, it MUST verify - the signature using the notification server's public key, discoverable via the storage - description resource. + [[!RFC9421]]. When a webhook endpoint receives a signed message, it MUST + verify the signature using the notification server's public key, discoverable via + the storage description resource.

    - A server that supports HTTP Message Signatures MUST include the public portion of - its signing key in the storage description resource using a - verificationMethod property. + A server that supports HTTP Message Signatures MUST include the signing key in the + storage description resource. The key MUST be expressed as a verification method + in a verificationMethod array, and MUST be referenced from an + authentication verification relationship, following the Controlled + Identifiers 1.0 [[!CID-1.0]] data model.

    -
    +        
     {
       "@context": ["https://www.w3.org/ns/lws/v1"],
       "id": "https://storage.example/",
    @@ -686,6 +758,7 @@ 

    Webhook Authentication

    "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0" } }], + "authentication": ["https://storage.example/#key-20260320"], "service": [{ "type": "NotificationService", "serviceEndpoint": "https://notification.example/subscriptions", @@ -768,8 +841,8 @@

    Subscription Management

    The value of the serviceEndpoint property for a NotificationService that supports WebhookSubscription - MUST be a URL that supports GET operations to list an agent's active - webhook subscriptions. The resulting serialization MUST conform to the requirements + MUST be a URL that supports GET operations to list a subscriber's + active webhook subscriptions. The resulting serialization MUST conform to the requirements for LWS Containers [[!LWS-PROTOCOL]]. The response SHOULD support LWS Paging.

    @@ -815,7 +888,7 @@

    Security Considerations

  • Webhook Verification: Without proper authentication on webhook - deliveries, an attacker could spoof notifications. Webhook receivers are strongly + deliveries, an attacker could spoof notifications. Subscribers are strongly encouraged to validate HTTP Message Signatures on all incoming notification requests using the public key published in the associated storage description resource.
  • @@ -825,21 +898,15 @@

    Security Considerations

  • Signature Replay: A signed webhook request could be captured and - replayed by an attacker. Webhook receivers are encouraged to check the + replayed by an attacker. Subscribers are encouraged to check the created parameter in the Signature-Input field and reject signatures whose timestamp falls outside a reasonable clock-skew window.
  • Information Disclosure: Notifications may reveal the existence or - modification patterns of resources. It is strongly recommended that access control on - subscriptions be consistent with access control on the underlying resources. -
  • -
  • - Phase Security: The phase property is defined with only - the post-commit value in this specification. Future specifications - defining additional lifecycle phases (such as pre-commit interception) MUST define - their own security requirements, particularly for synchronous request-response - patterns where a subscriber can influence resource persistence. + modification patterns of resources. Access control on subscriptions and on individual + notification delivery MUST be consistent with access control on the underlying + resources.
  • @@ -850,7 +917,7 @@

    Privacy Considerations

    • Activity Tracking: Notifications inherently reveal when resources - change. Subscribers SHOULD only receive notifications for resources they are + change. Subscribers SHOULD only receive notifications for resources they are authorized to access.
    • @@ -908,6 +975,11 @@

      Vocabulary

      lws:WebhookSubscription Webhook subscription type + + PostCommit + lws:PostCommit + Notification phase indicating an event occurred after resource persistence + subscriptionType lws:subscriptionType @@ -943,7 +1015,9 @@

      Vocabulary

      This document uses the following terms from external vocabularies, which should be - added to the LWS JSON-LD context: + added to the LWS JSON-LD context. The Activity Streams 2.0 terms are included in + the LWS context with their source IRIs from the + https://www.w3.org/ns/activitystreams# namespace.

      @@ -955,20 +1029,65 @@

      Vocabulary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + - + - + From 948b21b43d6d4323a6926b2dcab752b0058880e3 Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 13 Apr 2026 14:02:25 +0200 Subject: [PATCH 3/9] fix: clarify role of phase in envelope properties --- lws10-notifications/index.html | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lws10-notifications/index.html b/lws10-notifications/index.html index 2345b4f..7b6f853 100644 --- a/lws10-notifications/index.html +++ b/lws10-notifications/index.html @@ -201,6 +201,13 @@

      Notification Envelope

      Envelope Properties

      +

      + The notification envelope carries metadata about the delivery context alongside + the activity payload. This includes the originating storage, the subscription + type, and an optional phase indicating at which point in the resource lifecycle + the notification was emitted. +

      +

      A notification envelope has the following properties:

      @@ -211,9 +218,10 @@

      Envelope Properties

      Notification.
    • - phase — OPTIONAL. A string indicating the lifecycle phase - of the notification. This specification defines the value - PostCommit. + phase — OPTIONAL. A string indicating at which point in + the resource lifecycle the notification was emitted. This specification defines + the value PostCommit, which indicates that the described change + has already been persisted.
    • storage — REQUIRED. A URI identifying the LWS storage with From 923239f694c8727820309af166df29962ebfbb20 Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 13 Apr 2026 14:04:09 +0200 Subject: [PATCH 4/9] fix: editorial change --- lws10-notifications/index.html | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lws10-notifications/index.html b/lws10-notifications/index.html index 7b6f853..951b80e 100644 --- a/lws10-notifications/index.html +++ b/lws10-notifications/index.html @@ -201,13 +201,6 @@

      Notification Envelope

      Envelope Properties

      -

      - The notification envelope carries metadata about the delivery context alongside - the activity payload. This includes the originating storage, the subscription - type, and an optional phase indicating at which point in the resource lifecycle - the notification was emitted. -

      -

      A notification envelope has the following properties:

      From 1d32d69b913471ea93c5b76f3e504901dfc371e8 Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 13 Apr 2026 14:06:10 +0200 Subject: [PATCH 5/9] chore: complete authors section --- lws10-notifications/index.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lws10-notifications/index.html b/lws10-notifications/index.html index 951b80e..a34aa3a 100644 --- a/lws10-notifications/index.html +++ b/lws10-notifications/index.html @@ -13,10 +13,18 @@ name: "Jesse Wright", w3cid: "132252", company: "University of Oxford", - companyURL: "https://www.ox.ac.uk/" + companyURL: "https://www.ox.ac.uk/", + }, { + name: "Erich Bremer", + w3cid: "45759", + company: "Stony Brook University", + companyURL: "https://www.stonybrook.edu/", }], authors: [{ name: "Laurens Debackere" + }, + { + name: "Aaron Coburn" }], github: "w3c/lws-protocol", xref: ["web-platform"], From eedb68ffa9b50a60aec473c92b1d56839cd9c127 Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 13 Apr 2026 14:16:15 +0200 Subject: [PATCH 6/9] fix: unify inbox terminology, remove webhook endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the Webhook Endpoint term with Inbox — a URL controlled by a subscriber or other agent to which a server delivers notifications via HTTP POST. This aligns with the inbox concept used in the access-request-grant-proposal and makes the term reusable across LWS subspecifications. --- lws10-notifications/index.html | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lws10-notifications/index.html b/lws10-notifications/index.html index a34aa3a..9ee2c50 100644 --- a/lws10-notifications/index.html +++ b/lws10-notifications/index.html @@ -143,12 +143,14 @@

      Terminology

      receives the resulting notifications.
    • - Capability URL — a URL that encodes a subscription scope and - serves as the credential for establishing a notification connection. + Inbox — a URL controlled by a subscriber or other agent + to which a server delivers notifications via HTTP POST. An inbox is + used whenever the recipient of a notification is a server rather than a client + holding an open connection.
    • - Webhook Endpoint — a URL controlled by a subscriber to - which the server delivers notifications via HTTP. + Capability URL — a URL that encodes a subscription scope and + serves as the credential for establishing a notification connection.
    • @@ -650,8 +652,8 @@

      Webhook Notifications

      Webhooks enable server-to-server notification delivery. After a webhook subscription is - created, the LWS storage server delivers notifications to the registered - webhook endpoint of the subscriber when relevant changes occur. + created, the LWS storage server delivers notifications to the subscriber's + registered inbox when relevant changes occur.

      @@ -665,8 +667,8 @@

      Creating a Webhook Subscription

      • - inbox — REQUIRED. The URI of the endpoint to which notification - messages are sent. + inbox — REQUIRED. The URI of the inbox to which + notification messages are delivered.
      • expires — OPTIONAL. A datetime value indicating when the @@ -730,13 +732,13 @@

        Creating a Webhook Subscription

        Webhook Authentication

        - When a server delivers a notification to a webhook endpoint, the + When a server delivers a notification to an inbox, the subscriber needs to verify that the request is authentic.

        A server SHOULD sign each outbound request using HTTP Message Signatures - [[!RFC9421]]. When a webhook endpoint receives a signed message, it MUST + [[!RFC9421]]. When an inbox receives a signed message, it MUST verify the signature using the notification server's public key, discoverable via the storage description resource.

        @@ -788,11 +790,11 @@

        Signature Requirements

      • @method — the HTTP method of the request (always POST).
      • @scheme — prevents downgrade from https to http.
      • - @authority — the host of the webhook endpoint, + @authority — the host of the inbox, preventing delivery to an unintended endpoint.
      • - @path — the path component of the webhook endpoint URL. + @path — the path component of the inbox URL.
      • content-type — the media type of the request body. @@ -867,7 +869,7 @@

        Notification Delivery

        The server sends an HTTP POST request to the registered - webhook endpoint with the notification envelope as the request body. The + inbox with the notification envelope as the request body. The request body MUST conform to the application/lws+json media type.

        From 68deb8d4f4220d611810d8c7c53d30a4de6f2cfe Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 13 Apr 2026 15:49:53 +0200 Subject: [PATCH 7/9] Add overview of LWS Notifications spec to unstable features Reference the lws10-notifications specification with a summary of the three notification channels (SSE, WebSocket, Webhooks) and shared data model. --- lws10-core/Unstable-Features/Notifications.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lws10-core/Unstable-Features/Notifications.md b/lws10-core/Unstable-Features/Notifications.md index 76a99f3..14ab2e0 100644 --- a/lws10-core/Unstable-Features/Notifications.md +++ b/lws10-core/Unstable-Features/Notifications.md @@ -1,2 +1,9 @@ -this left intentionally blank +# Notifications +The [LWS Notifications](../../lws10-notifications/index.html) specification extends the Linked Web Storage (LWS) protocol with a mechanism for clients to receive timely updates about changes to resources. Three notification channels are defined: + +- **Server-Sent Events** — streaming updates over an EventSource connection +- **WebSocket** — real-time bidirectional notification channel +- **Webhooks** — server-to-server push notifications with HTTP Message Signatures + +All channels share a common notification data model based on Activity Streams and are discoverable via the storage description resource. From 29fa8fa84f4f8fd89214b863ef568e7a13fc6aff Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 13 Apr 2026 16:48:19 +0200 Subject: [PATCH 8/9] feat: add notification terms to vocabulary --- lws10-vocab/vocabulary.yml | 129 +++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/lws10-vocab/vocabulary.yml b/lws10-vocab/vocabulary.yml index d86e270..76dc3de 100644 --- a/lws10-vocab/vocabulary.yml +++ b/lws10-vocab/vocabulary.yml @@ -8,6 +8,10 @@ prefix: value: https://www.w3.org/ns/activitystreams# - id: schema value: https://schema.org/ + - id: sec + value: https://w3id.org/security# + - id: ldp + value: http://www.w3.org/ns/ldp# ontology: - property: dc:title @@ -41,6 +45,36 @@ class: comment: An OpenID Connect identity provider service. defined_by: https://www.w3.org/TR/lws-authn-openid/ + - id: Notification + label: Notification + comment: A notification envelope describing an event that occurred on a resource. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: NotificationService + label: Notification Service + comment: A service through which clients subscribe to resource change notifications. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: WebSocketSubscription + label: WebSocket Subscription + comment: A subscription type that delivers notifications over a WebSocket connection. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: EventSourceSubscription + label: EventSource Subscription + comment: A subscription type that delivers notifications over a Server-Sent Events connection. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: WebhookSubscription + label: Webhook Subscription + comment: A subscription type that delivers notifications via HTTP POST to a subscriber-provided inbox URL. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: PostCommit + label: Post Commit + comment: A notification phase indicating the event occurred after the resource change was persisted. + defined_by: https://www.w3.org/TR/lws-notifications/ + property: - id: items label: items @@ -93,6 +127,101 @@ property: label: Prefer Link Relations comment: A preference URI for including or omitting specific link relations in responses. + - id: subscriptionType + label: subscription type + domain: lws:NotificationService + comment: The subscription types supported by a notification service. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: subscription + label: subscription + range: xsd:anyURI + comment: The URL of the subscription resource or connection endpoint. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: phase + label: phase + domain: lws:Notification + comment: The lifecycle phase at which the notification was emitted. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: activity + label: activity + domain: lws:Notification + comment: The Activity Streams 2.0 activity payload within a notification. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: topic + label: topic + range: xsd:anyURI + comment: An array of resource URIs covered by a subscription. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: storage + label: storage + range: xsd:anyURI + comment: The URI identifying the LWS storage that emitted the notification. + defined_by: https://www.w3.org/TR/lws-notifications/ + + - id: as:Create + label: Create + comment: An activity representing the creation of a resource. + + - id: as:Update + label: Update + comment: An activity representing the update of a resource. + + - id: as:Delete + label: Delete + comment: An activity representing the deletion of a resource. + + - id: as:object + label: object + comment: The primary object of an activity. + + - id: as:actor + label: actor + comment: The agent that performed the activity. + + - id: as:target + label: target + comment: The target of the activity. + + - id: as:origin + label: origin + comment: The origin of a Move activity. + + - id: as:published + label: published + range: xsd:dateTime + comment: The date and time the activity was published. + + - id: sec:verificationMethod + label: verification method + comment: A verification method associated with a key or identity. + + - id: sec:authentication + label: authentication + comment: An authentication method associated with an identity. + + - id: sec:controller + label: controller + comment: The entity that controls a verification method. + + - id: sec:publicKeyJwk + label: public key JWK + comment: A public key expressed as a JSON Web Key. + + - id: ldp:inbox + label: inbox + range: xsd:anyURI + comment: A URL to which notifications are delivered via HTTP POST. + + - id: schema:expires + label: expires + range: xsd:dateTime + comment: The date and time at which a subscription expires. + json_ld: alias: id: "@id" From 9c7b303ee4136342c2c6ebae58c0393e7101b233 Mon Sep 17 00:00:00 2001 From: Laurens Debackere Date: Mon, 18 May 2026 13:47:22 +0200 Subject: [PATCH 9/9] refactor: scope notifications spec to webhooks only, remove phase Remove WebSocket and Server-Sent Event notification channels from the base notifications specification. These client-server streaming channels will be introduced in a separate specification. Remove the phase property from the notification envelope and subscription request. This concept may be re-introduced at a later point. --- lws10-core/Discovery.html | 2 +- lws10-core/Unstable-Features/Notifications.md | 8 +- lws10-notifications/index.html | 216 +----------------- lws10-vocab/vocabulary.yml | 21 -- 4 files changed, 13 insertions(+), 234 deletions(-) diff --git a/lws10-core/Discovery.html b/lws10-core/Discovery.html index 9b63bc0..90f960f 100644 --- a/lws10-core/Discovery.html +++ b/lws10-core/Discovery.html @@ -126,7 +126,7 @@

        Storage Description Representation

        "service": [{ "type": "NotificationService", "serviceEndpoint": "https://storage.example/notification/api", - "subscriptionType": ["WebhookSubscription", "WebSocketSubscription", "EventSourceSubscription"] + "subscriptionType": ["WebhookSubscription"] }, { "type": "TypeIndexService", "serviceEndpoint": "https://storage.example/types/api" diff --git a/lws10-core/Unstable-Features/Notifications.md b/lws10-core/Unstable-Features/Notifications.md index 14ab2e0..0a6198d 100644 --- a/lws10-core/Unstable-Features/Notifications.md +++ b/lws10-core/Unstable-Features/Notifications.md @@ -1,9 +1,5 @@ # Notifications -The [LWS Notifications](../../lws10-notifications/index.html) specification extends the Linked Web Storage (LWS) protocol with a mechanism for clients to receive timely updates about changes to resources. Three notification channels are defined: +The [LWS Notifications](../../lws10-notifications/index.html) specification extends the Linked Web Storage (LWS) protocol with a mechanism for clients to receive timely updates about changes to resources via Webhooks — server-to-server push notifications with HTTP Message Signatures. -- **Server-Sent Events** — streaming updates over an EventSource connection -- **WebSocket** — real-time bidirectional notification channel -- **Webhooks** — server-to-server push notifications with HTTP Message Signatures - -All channels share a common notification data model based on Activity Streams and are discoverable via the storage description resource. +The notification data model is based on Activity Streams and is discoverable via the storage description resource. diff --git a/lws10-notifications/index.html b/lws10-notifications/index.html index 9ee2c50..0b83a96 100644 --- a/lws10-notifications/index.html +++ b/lws10-notifications/index.html @@ -63,9 +63,9 @@

        This document extends the Linked Web Storage (LWS) protocol with a mechanism for clients - to receive timely updates about changes to resources. Three notification channels are - defined: Server-Sent Events, WebSocket, and Webhooks. All channels share a common - notification data model and are discoverable via the storage description resource. + to receive timely updates about changes to resources via Webhooks. The specification + defines a common notification data model and is discoverable via the storage description + resource.

        @@ -86,27 +86,9 @@

        Introduction

        This specification extends LWS with a notification mechanism that allows clients - to subscribe to resource changes and receive updates through one of three channels: -

        - -
          -
        • - Server-Sent Events (SSE): A client opens a persistent HTTP connection - and receives real-time change events as a stream of server-sent events. -
        • -
        • - WebSocket: A client opens a persistent WebSocket connection and receives - real-time change events as WebSocket messages. -
        • -
        • - Webhooks: A server-to-server mechanism whereby the LWS storage server - delivers change events to a registered endpoint via HTTP POST. -
        • -
        - -

        - All three channels share a common notification envelope and are discoverable - via the storage description resource. + to subscribe to resource changes and receive updates via Webhooks — a + server-to-server mechanism whereby the LWS storage server delivers change events to a + registered endpoint via HTTP POST.

        @@ -184,9 +166,7 @@

        Discovery

        "type": "NotificationService", "serviceEndpoint": "https://notification.example/subscriptions", "subscriptionType": [ - "WebhookSubscription", - "WebSocketSubscription", - "EventSourceSubscription" + "WebhookSubscription" ] }] } @@ -220,12 +200,6 @@

        Envelope Properties

        type — REQUIRED. The value MUST be the string Notification.
      • -
      • - phase — OPTIONAL. A string indicating at which point in - the resource lifecycle the notification was emitted. This specification defines - the value PostCommit, which indicates that the described change - has already been persisted. -
      • storage — REQUIRED. A URI identifying the LWS storage with which the notification is associated. @@ -244,7 +218,6 @@

        Envelope Properties

        "https://www.w3.org/ns/activitystreams" ], "type": "Notification", - "phase": "PostCommit", "storage": "https://storage.example/", "activity": { "id": "ec4dcc48-6581-4232-81c9-584525a98693", @@ -360,7 +333,6 @@

        Batching Notifications

        "https://www.w3.org/ns/activitystreams" ], "type": "Notification", - "phase": "PostCommit", "storage": "https://storage.example/", "activity": [ { @@ -417,18 +389,6 @@

        Subscription Request

      -

      - A subscription request MAY contain the following fields: -

      - -
        -
      • - phase — OPTIONAL. A string indicating the lifecycle phase for - which notifications are requested. This specification defines the value - PostCommit. -
      • -
      -

      A subscription request MAY contain additional fields as required by the specific subscription type. @@ -442,12 +402,12 @@

      Subscription Request

      { "@context": ["https://www.w3.org/ns/lws/v1"], - "type": "EventSourceSubscription", - "phase": "PostCommit", + "type": "WebhookSubscription", "topic": [ "https://storage.example/alice/notes/", "https://storage.example/alice/profile" - ] + ], + "inbox": "https://receiver.example/hooks/lws" }
      @@ -517,136 +477,6 @@

      Subscription Response

      -
      -

      WebSocket Notifications

      - -

      - The WebSocket notification channel allows a subscriber to receive notifications - over a persistent WebSocket connection. -

      - -
      -

      Creating a WebSocket Subscription

      - -

      - When a client creates a WebSocket notification subscription, the subscription body - MUST include a type field equal to WebSocketSubscription. -

      - -

      - A successful response body has these additional requirements: -

      - -
        -
      • - type — the value of this property MUST be a string equal to - WebSocketSubscription. -
      • -
      • - subscription — the value of this property MUST be a - capability URL that can be used by the WebSocket API. -
      • -
      - -
      -{
      -  "@context": ["https://www.w3.org/ns/lws/v1"],
      -  "type": "WebSocketSubscription",
      -  "subscription": "wss://notification.example/ws/1c2d3e4f5a6b"
      -}
      -        
      -
      - -
      -

      Establishing a WebSocket Connection

      - -

      - After obtaining a capability URL, the subscriber opens a WebSocket - connection to that URL. The server sends notification envelopes as WebSocket text - messages, serialized as JSON. -

      - -
      -const ws = new WebSocket(capabilityUrl);
      -ws.onmessage = (event) => {
      -  const notification = JSON.parse(event.data);
      -  // handle notification
      -};
      -        
      - -

      - The lifecycle of a WebSocket subscription is tied to the connection. When the - WebSocket connection is closed, the subscription is terminated. -

      -
      -
      - -
      -

      Server-Sent Event Notifications

      - -

      - The Server-Sent Event (SSE) notification channel allows a subscriber to receive - notifications over a persistent HTTP connection using the EventSource API. -

      - -
      -

      Creating an EventSource Subscription

      - -

      - When a client creates an EventSource notification subscription, the subscription body - MUST include a type field equal to EventSourceSubscription. -

      - -

      - A successful response body has these additional requirements: -

      - -
        -
      • - type — the value of this property MUST be a string equal to - EventSourceSubscription. -
      • -
      • - subscription — the value of this property MUST be a - capability URL that can be used by the EventSource API. -
      • -
      - -
      -{
      -  "@context": ["https://www.w3.org/ns/lws/v1"],
      -  "type": "EventSourceSubscription",
      -  "subscription": "https://notification.example/sse/0d8b4c2e1a3f"
      -}
      -        
      -
      - -
      -

      Establishing an EventSource Connection

      - -

      - After obtaining a capability URL, the subscriber establishes a - persistent SSE connection to that URL. The server responds with Content-Type: - text/event-stream and pushes notification envelopes as events. Each event - MUST include an id field to support reconnection via the - Last-Event-ID header. -

      - -
      -const source = new EventSource(capabilityUrl);
      -source.onmessage = (event) => {
      -  const notification = JSON.parse(event.data);
      -  // handle notification
      -};
      -        
      - -

      - The lifecycle of an EventSource subscription is tied to the connection. When - the connection is closed, the subscription is terminated. -

      -
      -
      -

      Webhook Notifications

      @@ -685,7 +515,6 @@

      Creating a Webhook Subscription

      { "@context": ["https://www.w3.org/ns/lws/v1"], "type": "WebhookSubscription", - "phase": "PostCommit", "topic": [ "https://storage.example/alice/notes/", "https://storage.example/alice/profile" @@ -892,11 +721,6 @@

      Notification Delivery

      Security Considerations

        -
      • - Token Leakage: Capability URLs used with SSE and WebSocket - channels might be visible in server logs and a browser's history. Mitigations include - using short-lived and single-use URLs. -
      • Webhook Verification: Without proper authentication on webhook deliveries, an attacker could spoof notifications. Subscribers are strongly @@ -971,26 +795,11 @@

        Vocabulary

      - - - - - - - - - - - - - - - @@ -1001,11 +810,6 @@

      Vocabulary

      - - - - - diff --git a/lws10-vocab/vocabulary.yml b/lws10-vocab/vocabulary.yml index 76dc3de..773c0b8 100644 --- a/lws10-vocab/vocabulary.yml +++ b/lws10-vocab/vocabulary.yml @@ -55,26 +55,11 @@ class: comment: A service through which clients subscribe to resource change notifications. defined_by: https://www.w3.org/TR/lws-notifications/ - - id: WebSocketSubscription - label: WebSocket Subscription - comment: A subscription type that delivers notifications over a WebSocket connection. - defined_by: https://www.w3.org/TR/lws-notifications/ - - - id: EventSourceSubscription - label: EventSource Subscription - comment: A subscription type that delivers notifications over a Server-Sent Events connection. - defined_by: https://www.w3.org/TR/lws-notifications/ - - id: WebhookSubscription label: Webhook Subscription comment: A subscription type that delivers notifications via HTTP POST to a subscriber-provided inbox URL. defined_by: https://www.w3.org/TR/lws-notifications/ - - id: PostCommit - label: Post Commit - comment: A notification phase indicating the event occurred after the resource change was persisted. - defined_by: https://www.w3.org/TR/lws-notifications/ - property: - id: items label: items @@ -139,12 +124,6 @@ property: comment: The URL of the subscription resource or connection endpoint. defined_by: https://www.w3.org/TR/lws-notifications/ - - id: phase - label: phase - domain: lws:Notification - comment: The lifecycle phase at which the notification was emitted. - defined_by: https://www.w3.org/TR/lws-notifications/ - - id: activity label: activity domain: lws:Notification
      Createhttps://www.w3.org/ns/activitystreams#CreateActivity Streams 2.0
      Updatehttps://www.w3.org/ns/activitystreams#UpdateActivity Streams 2.0
      Deletehttps://www.w3.org/ns/activitystreams#DeleteActivity Streams 2.0
      objecthttps://www.w3.org/ns/activitystreams#objectActivity Streams 2.0
      actorhttps://www.w3.org/ns/activitystreams#actorActivity Streams 2.0
      targethttps://www.w3.org/ns/activitystreams#targetActivity Streams 2.0
      originhttps://www.w3.org/ns/activitystreams#originActivity Streams 2.0
      publishedhttps://www.w3.org/ns/activitystreams#publishedActivity Streams 2.0
      verificationMethod https://w3id.org/security#verificationMethodSecurity VocabularyControlled Identifiers 1.0
      authenticationhttps://w3id.org/security#authenticationMethodControlled Identifiers 1.0
      controller https://w3id.org/security#controllerSecurity VocabularyControlled Identifiers 1.0
      publicKeyJwk https://w3id.org/security#publicKeyJwkSecurity VocabularyControlled Identifiers 1.0
      inboxlws:NotificationService Service type for notification discovery
      WebSocketSubscriptionlws:WebSocketSubscriptionWebSocket subscription type
      EventSourceSubscriptionlws:EventSourceSubscriptionServer-Sent Event subscription type
      WebhookSubscription lws:WebhookSubscription Webhook subscription type
      PostCommitlws:PostCommitNotification phase indicating an event occurred after resource persistence
      subscriptionType lws:subscriptionType lws:subscription URL of the subscription resource
      phaselws:phaseLifecycle phase of the notification
      activity lws:activity