This document defines a Webhook-based notification suite for the Linked Web Storage (LWS) protocol, enabling LWS servers to deliver resource change notifications to registered endpoints via HTTP POST.
This is an unofficial proposal.
The [[!LWS10-CORE|Linked Web Storage]] protocol defines a notification mechanism that allows clients to subscribe to resource changes and receive updates through various delivery channels. This document describes the Webhook notification suite — a server-to-server mechanism whereby the LWS storage server delivers change events to a registered endpoint via HTTP POST.
The terms "notification", "subscription", "subscriber", "notification suite", "storage description resource", and "agent" are defined by the Linked Web Storage Protocol [[!LWS10-CORE]].
The terms "controlled identifier document", "verification method", and "verification relationship" are defined by Controlled Identifiers 1.0 [[!CID-1.0]].
This specification defines the following additional terms:
POST. An inbox is
used whenever the recipient of a notification is a server rather than a client
holding an open connection.
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 inbox to which
notification messages are delivered.
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",
"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"
}
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 an inbox 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 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/",
"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"
}
}],
"authentication": ["https://storage.example/#key-20260320"],
"service": [{
"type": "NotificationService",
"serviceEndpoint": "https://notification.example/subscriptions",
"subscriptionType": ["WebhookSubscription"]
}]
}
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 inbox,
preventing delivery to an unintended endpoint.
@path — the path component of the inbox 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.
To verify a webhook signature, a receiver MUST perform the following steps:
keyid value from the Signature-Input
field. The keyid value MUST be a URL with a fragment component.
keyid URL. The resulting
URL is the storage identifier.
id property of the top-level document map MUST match the
storage identifier.
verificationMethod array whose
id property matches either the full keyid URL or the
fragment component of the keyid URL.
The value of the serviceEndpoint property for a
NotificationService that supports WebhookSubscription
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 [[!LWS10-CORE]]. 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.
The server sends an HTTP POST request to the registered
inbox with the notification envelope as the request body. The
request body MUST conform to the application/lws+json media type.
A Webhook subscription MUST use the WebhookSubscription string
as its subscription type when interacting with the NotificationService.
created parameter in the Signature-Input field and reject
signatures whose timestamp falls outside a reasonable clock-skew window.