Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Solid Notifications proposal #3

Merged
merged 3 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added proposals/solid-notifications-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
270 changes: 270 additions & 0 deletions proposals/solid-notifications.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
# Solid Notifications

**Status**: Proposal

## Introduction

Much of the Solid Protocol is built on a RESTful API. This allows Solid to make use of well-understood interactions with resources on the Web, and this satisfies many use cases for client applications in the Solid ecosystem. However, for interactive client applications with multiple participants, chat-apps being just one such example, a RESTful API is too limited, as clients need to rely on polling in order to discover changes in the underlying data.

A notification API for Solid would complement the core RESTful API so that clients can listen for updates to particular resources. In addition, a notification-based mechanism may reduce latency and load on a Pod server.

Copy link

Choose a reason for hiding this comment

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

Add a mention that existing Sold servers and clients implementing a notification protocol based on web sockets, and this being used for example for chat applications, collaborative editors, etc. It is disingenuous to write as though this is not currently already running. This protocol serves to provide a more secure and more modular version of the same functionality.

Copy link
Member Author

Choose a reason for hiding this comment

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

Noted. The introduction text will likely be completely rewritten. Does this concern block merging this PR in its present form?

Choose a reason for hiding this comment

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

#12

One challenge with (near) real-time notifications on the Web involves the diversity of technologies available. WebSockets and EventSource APIs are two options that are widely supported by browsers; ReadableStreams are becoming more widely supported. Furthermore, there are other, more asynchronous models that are relevant in certain cases: WebHooks, WebSub and Linked Data Notifications are three examples. A major goal of the model described in this document is to make it possible for client applications to navigate the diversity of these technologies while also being open to new notification mechanisms as they emerge.

Finally, a critically important part of this model is security. Any notification-based API not only needs the same level of security that is found in the RESTful API but also the authorization mechanism needs to be consistent across these endpoints.

## Use Cases

1. **Immediate notification of data changes** - for many clients, it is important to know when a resource state changes. This includes collaborative editing apps, chat apps or any client that expects the underlying data to change frequently based on updates made by others.
1. **Change frequency** - sometimes a client doesn't need to be alerted for every change. If a client only needs infrequent updates, for example, every 5 minutes, it should be possible to avoid floods of data that might otherwise place a higher burden on the client application. Ideally, a client should be able to define what that aggregation window would be: for some clients, 10 seconds might be appropriate; for others, several minutes might be more appropriate.
1. **Filtered notifications** - certain categories of notifications may be more or less interesting to clients. For example, a client may not care about UPDATE operations or may only care about notifications for resources of certain types.
1. **Time-bound subscriptions** - occasionally, a client only needs a subscription to be in effect for a limited period of time. While a client may easily close a WebSocket itself, subscriptions for other, more asynchronous forms of notifications, such as LDN alerts or WebHook operations, may be more difficult to terminate.
1. **Avoiding missing updates** - for WebSockets and protocols that rely on an active, live connection to a notification server, the notification protocol needs to make sure that clients do not miss notifications in the event of a dropped connection.
1. **Protocol negotiation** - a given Solid Notification server may support certain technologies (e.g. WebSockets and LDN) but not others (e.g. EventSource and WebSub). Likewise, a client may not support the same set of protocols that are implemented by a server. As such, there needs to be a mechanism for clients and servers to agree on a mutually supported protocol. In addition to simply determining the set of protocols that work for client and server, there may be particular features (e.g. notification aggregation, notification filtering) that are required for the client. This could be used to further filter the protocol selection.
1. **Security** - a client should not be able to subscribe to resources to which it does not have read access.
Copy link
Member

Choose a reason for hiding this comment

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

It may also be worth mentioning that a client should be able to trust that the notifications it receives aren't forged.

Choose a reason for hiding this comment

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

#10


## Terminology

This document uses terms from the Solid Protocol specification, including "data pod". This document also uses terms from the OAuth2 specification, including "resource server", "authorization server" and "client", as well as terms from the WebSub specification, including "topic".

In addition, the following terms are defined:

**Notification Gateway API** -- an HTTP endpoint at which a client can negotiate an acceptable notification subscription location

**Notification Subscription API** -- an HTTP endpoint at which a client can initiate a subscription to notification events for a particular set of resources

**Solid Server Metadata Resource** - an RDF document that includes metadata about the Solid server

## High-level Flow

The following diagram shows the high level interactions involved in this flow. How a client retrieves an access token for step 5 is outside the scope of this document.

![High level flow](solid-notifications-flow.png)

## Discovery

For any resource in a data pod, a client can discover the associated notification gateway API by fetching the Solid Server Metadata Resource. This resource can be retrieved by appending /.well-known/solid to the base URL of the data pod.

```http
GET /.well-known/solid
```

The server `MUST` be capable of serializing this resource as Turtle or JSON-LD.

A sample representation of this resource might include the following:

```http
Content-Type: application/ld+json

{
"@context": ["https://www.w3.org/ns/solid/notification/v1"],
"notification_endpoint": "https://gateway.example",
...
}
```

**Note**: the notification panel should define a particular JSON-LD @context for use with JSON-LD serializations.

**Note**: the use of a well-known resource is based on suggestions to avoid too many link headers, but that is not a settled issue.
Copy link
Member

Choose a reason for hiding this comment

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

Just a general comment that I like this use of .well-known as a discovery mechanism for server support. It has broad adoption in other protocols, fits nicely here, and would useful for other things, like whether a server supports / enforces data validation, etc.


## Protocol

The notification protocol involves two endpoints: a notification gateway API and a notification subscription API. A server `MUST` support JSON-LD in these interactions.

### Notification Gateway
Once the location of a notification gateway is discovered, an application will negotiate for a particular notification channel, based on acceptable features and protocols.

The `type` array advertises which subscription channels a client is able to understand. The `features` array advertises which notification features are required by the client. The server selects one of the proposed subscription types and responds with a JSON-LD document that includes the selected protocol, the endpoint for negotiating a subscription and the supported features offered by that protocol.

Authentication is not required at this endpoint.

A sample interaction is described below. The type and feature names are included as examples.

#### Request

```http
POST /gateway
Content-Type: application/ld+json

{
"@context": ["https://www.w3.org/ns/solid/notification/v1"],
"type": ["WebSocketSubscription2021", "WebHookSubscription2021"],
"features": ["state", "rate"]
}
```

#### Response

```http
HTTP/2
Content-Type: application/ld+json

{
"@context": ["https://www.w3.org/ns/solid/notification/v1"],
"type": "WebSocketSubscription2021",

Choose a reason for hiding this comment

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

For clarification, I assume the server will only respond with a(?) subscription channel that is supported by the client. What happens if there are none? Or if there is multiple? (In the latter case, I assume it will then be up to the client to decide which one to use).

Copy link
Member Author

Choose a reason for hiding this comment

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

A server responds with either a single subscription channel or returns a 4xx error.

Choose a reason for hiding this comment

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

OK. As only a single channel will be returned, I would suggest that the request lists the types in preferred order just in case there is multiple overlap.

Choose a reason for hiding this comment

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

#9

"endpoint": "https://websocket.example/subscription",
"features": ["state", "rate", "expiration", "feature1", "feature2"]
}
```

**Note**: the features array may not be needed as part of this negotiation.

### Notification Subscription

The details of subscribing to a particular endpoint depend on the technology used, but all will follow a similar pattern. For WebSockets, this involves sending an authenticated subscription request to the endpoint retrieved from the gateway service.

The client sends a JSON-LD payload to this endpoint via POST. The only required fields in this interaction are type and topic. The type field MUST contain the type of subscription being requested. The topic field MUST contain the URL of the resource a client wishes to subscribe to changes.

All other fields are defined by the particular subscription type. Some common features are described in the Features section of this document.

An example POST request using a DPoP bound access token is below:

```http
POST /subscription
Authorization: DPoP <token>
DPoP: <proof>
Content-Type: application/ld+json

{
"@context": ["https://www.w3.org/ns/solid/notification/v1"],
"type": "WebSocketSubscription2021",
"topic": "https://pod.example/resource",
"state": "opaque-state",
"expiration": "2021-09-21T12:37:15Z",
"rate": "PT10s"
}
```

A successful response will contain a URL that can be used directly with a JavaScript client

```http
HTTP/2
Content-Type: application/ld+json

{
"@context": "https://www.w3.org/ns/solid/notification/v1",
"type": "WebSocketSubscription2021",
"endpoint": "wss://websocket.example/?auth=Ys3KiUq"
}
```

In JavaScript, a client can use the data in the response to establish a connection to the WebSocket endpoint.

```javascript
const ws = new WebSocket(endpoint, type)
```

A client will define how to handle events, especially the onclose and onmessage events.

```javascript
ws.onclose(evt => reconnect(evt));
ws.onmessage(evt => console.log("Message received: ", evt))
```

## Authentication and Authorization

The Subscription API requires authorization. This document does not define the specific technology used to authorize requests; rather, it defers to the Solid Protocol sections on Authentication and Authorization. It is out of scope for this document to describe how a client fetches an authorization token. Solid-OIDC is one example of an authentication mechanism that could be used with Solid Notifications.
Copy link

Choose a reason for hiding this comment

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

The solid spec must define the whole protocol, including how the auth plugs into the notification. Propose that this document does define that. Otherwise we need another parallel document alongside this. The spec must completely define exactly ow to build a solid server.

Copy link
Member Author

Choose a reason for hiding this comment

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

Noted. Authorization is a topic that will need quite a bit of discussion in the panel and deserves its own dedicated thread. Does this concern block merging this PR in its present form?

Choose a reason for hiding this comment

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

#13


Resource-based Access controls MUST be enforced for every subscription. A client MUST be permitted to read the resource to which it subscribes.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Resource-based Access controls MUST be enforced for every subscription. A client MUST be permitted to read the resource to which it subscribes.
Resource-based Access controls MUST be enforced for every subscription. A client MUST be permitted to read the resources to which it subscribes.

Suggest pluralizing, since we should be able to subscribe eventually to topics that apply to multiple resources.

Copy link
Member Author

Choose a reason for hiding this comment

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

The challenge of subscribing to multiple resources on a single channel is that other features of this interaction fall apart.

For instance, if state refers to the last state of a resource, what does it mean for multiple resources?
If a client accepts updates at only a certain rate, what happens if two messages appear from different resources? Is one dropped?

At the underlying TCP layer (when HTTP/2 is used), all of the interactions occur over a single TCP socket, so there isn't additional network overhead when opening multiple such connections.


## Notification Data Model

The content of a Solid Notification is defined in terms of a W3C Activity Streams 2.0 document. As such, JSON-LD 1.0 is a required baseline serialization format, though other formats are not prohibited. JSON-LD version 1.1 is recommended when using JSON-LD serializations.

```javascript
{
"@context":[
"https://www.w3.org/ns/activitystreams",
"https://www.w3.org/ns/solid/notification/v1"
],
"id":"urn:uuid:<uuid>",
"type":[
"Update"
],
"actor":[
"<WebID>"
],
"object":{
Copy link

Choose a reason for hiding this comment

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

Suggest a level 2 protocol in which the triples which changed in an RDF resource are included in the notification.

Copy link
Member Author

Choose a reason for hiding this comment

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

Noted. The contents of a notification will be discussed and deserves its own thread of conversation. Does this concern block merging this PR in its present form?

Choose a reason for hiding this comment

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

#14

"id":"https://pod.inrupt.com/<user>/some-container/",
"type":[
"http://www.w3.org/ns/ldp#BasicContainer",
"http://www.w3.org/ns/ldp#Resource",
"http://example.com/SomeType"
]
},
"state": "1234-5678-90ab-cdef-12345678",
"published":"2021-08-05T01:01:49.550044Z"
}
```

**Note**: the Solid JSON-LD context resource does not currently exist. An implementation may choose to augment the context definition.

The content of these serialized notifications may be extended, but the example here provides a minimal baseline that clients can expect.

## Subscription Types

This document defines four initial subscription types:

* `WebSocketSubscription2021`
* `EventSourceSubscription2021`
* `LinkedDataNotificationSubscription2021`
* `WebHookSubscription2021`

**Note**: the naming convention used here follows a pattern used by the Verifiable Credentials community, making it possible to distinguish between different versions of these subscription types. Other naming conventions can achieve the same end.

Choose a reason for hiding this comment

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

To hide some of the complexity, would there be any advantage of having a universal notifications layer that will handle common elements of the different subscription types (similar in idea as solid/authorization-panel#253 for authorization)?

Choose a reason for hiding this comment

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

#11

### WebSocketSubscription2021

The `WebSocketSubscription2021` type defines the following properties:

* `endpoint`: this property is used in the body of the subscription response. The value of this property MUST be a URI, using the wss scheme. A JavaScript client would use the entire value as input to the WebSocket constructor.

### EventSourceSubscription2021

The `EventSourceSubscription2021` type defines the following properties:

* `endpoint`: this property is used in the body of the subscription response. The value of this property MUST be a URI, using the https scheme. A JavaScript client would use the entire value as input to the EventSource constructor.

### LinkedDataNotificationSubscription2021

The `LinkedDataNotificationSubscription2021` type defines the following properties:

* `inbox`: this property is used in the body of the subscription request. The value of this property MUST be a URI, using the https scheme. The inbox URI MUST conform to the receiver portion of the Linked Data Notification specification.
* `webid`: this property is used in the body of the subscription response. The value of this property MUST be an HTTPS URI conforming to the WebID draft specification. All LDN notifications will be sent to the defined inbox using the agent identity specified by this WebID. A resource owner should ensure that the agent identified in this property is permitted to send authenticated HTTP requests to the defined inbox.

### WebHookSubscription2021

The `WebHookSubscription2021` type defines the following properties:

* `target`: this property is used in the body of the subscription request. The value of this property MUST be a URI, using the https scheme.

## Features

Features allow clients to customize the details of a subscription. Some features are specific to particular subscription types while others may be used across all types. These shared features are listed as an initial baseline, though not all subscription types are required to implement these.

* `expiration`: an ISO 8601 datetime value indicating a proposed expiration point for a subscription. A server may choose another value.
* `state`: an opaque value representing the last known state of a resource. If the resource state is known to have changed when the client establishes a subscription, an initial notification must be sent to the client. This value should correspond to a resource's ETag header value.
* `rate`: an ISO 8601 duration value indicating the minimum amount of time to elapse between notifications sent to the client
* `accept`: a MIME-Type value that indicates the desired serialization of the notification. For instance, text/turtle may be acceptable.

Individual subscription types may define type-specific features.

**Note**: The list of common, shared features is not intended to be exhaustive.

## Extensions

There are two main axes of extension for this design: subscription type (e.g. `WebSocketSubscription2021` vs. `LinkedDataNotificationSubscription2021`) and notification features (e.g. `expiration` vs. `state`).

## References

* Solid Protocol: https://solidproject.org/TR/protocol
* Solid-OIDC: https://solid.github.io/solid-oidc/
* W3C Activity Streams 2.0: https://www.w3.org/TR/activitystreams-core/
* W3C JSON-LD 1.1: https://www.w3.org/TR/json-ld11/
* W3C Linked Data Notifications: https://www.w3.org/TR/ldn/
* W3C RDF 1.1 Concepts and Abstract Syntax: https://www.w3.org/TR/rdf11-concepts/
* W3C RDF 1.1 Turtle: https://www.w3.org/TR/turtle/
* W3C WebSub: https://www.w3.org/TR/websub/
* W3C WebID: https://www.w3.org/2005/Incubator/webid/spec/identity/
* The OAuth 2.0 Authorization Framework (RFC 6749): https://datatracker.ietf.org/doc/html/rfc6749
* OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer (DPoP): https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop-03
* Web sockets: https://html.spec.whatwg.org/multipage/web-sockets.html