Solid compliance

Solid (Social Linked Data) is a set of specifications whose aim is to allow users to store all their data in Pods (“Personal Online Datastores”). Users have full control over their data and can give permissions to applications or people they trust.

ActivityPods supports fully the philosophy behind Solid, but it doesn’t yet support all the standards that have been defined for Solid. It is thus not Solid compliant. However, we are keeping a close eye on the development of this standard and are gradually moving towards it, with the aim of being fully Solid compliant.

Linked Data Platform

Each Solid Pod must comply with the Linked Data Platform protocol. This is a REST-based API for managing containers and resources.

Formats

We support both JSON-LD and Turtle format.

Containers

We support the BasicContainer type, as required by the Solid specs.

Binaries

We support non-RDF resources (binaries) uploads. The description of the resource is stored in the triplestore as a http://semapps.org/ns/core#File.

<https://mypod.store/alice/data/files/picture.jpg>
   a <http://semapps.org/ns/core#File> ;
   <http://semapps.org/ns/core#fileName> "picture.jpg" ;
   <http://semapps.org/ns/core#localPath> "uploads/files/picture.jpg" ;
   <http://semapps.org/ns/core#mimeType> "image/jpeg" .

There is an issue to use the Solid recommended metadata instead.

PATCH method

LDP resources and containers can be selectively modified using the HTTP PATCH method. This method is important because it limits the risk of overwriting data, as with the simpler PUT method. However, due to the way RDF resources are formatted, the PATCH method cannot be used like more regular REST-based APIs. Many solutions have been proposed in the semantic web community to solve this problem:

Initially, the recommended method for Solid servers was SparqlPatch and this is what we implemented. In 2021, it was switched to a new N3 Patch method, as described in the Solid spec. It is not yet a W3C standard.

Until the N3 Patch method is standardized, we will continue to use the SparqlPatch format.

Example of a SparqlPatch update to modify a LDP resource.
PATCH /alice HTTP/1.1
Host: mypod.store
Content-Type: application/sparql-update

PREFIX as: <https://www.w3.org/ns/activitystreams#>
INSERT DATA { <https://mypod.store/alice> as:preferredUsername "Alice" . };
DELETE DATA { <https://mypod.store/alice> as:preferredUsername "ALICE" . };
Example of a SparqlPatch update to add or remove a resource from a LDP container.
PATCH /alice/data/events HTTP/1.1
Host: mypod.store
Content-Type: application/sparql-update

PREFIX ldp: <http://www.w3.org/ns/ldp#>
INSERT DATA { <http://mypod.store/alice/data/events> ldp:contains <http://url/of/resource/to/attach>. };
DELETE DATA { <http://mypod.store/alice/data/events> ldp:contains <http://url/of/resource/to/detach>. };

LDP Prefer header

👷 To be implemented. (#1168)

LDP paging

👷 To be implemented. (#176)

Identity

WebID

All ActivityPub actors are also WebIDs.

Click to see how an ActivityPods WebID looks like
{
	"@context": "https://activitypods.org/context.json",
	"id": "https://mypod.store/alice",
	"type": ["foaf:Person", "Person"],
	"dc:created": "2023-01-13T11:42:45.636Z",
	"dc:modified": "2023-01-13T11:42:48.389Z",
	"foaf:nick": "alice",
	"preferredUsername": "alice",
	"inbox": "https://mypod.store/alice/inbox",
	"outbox": "https://mypod.store/alice/outbox",
	"followers": "https://mypod.store/alice/followers",
	"following": "https://mypod.store/alice/following",
	"liked": "https://mypod.store/alice/liked",
	"publicKey": {
		"owner": "https://mypod.store/alice",
		"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzlq6avqA4nwxGDqXMijZ\nixRIllyIDkF4rc9KxUHizysOJEBx9+WSfom0wlS1hPr+Qn90eb8h/8wjbvfXdjYm\npdusaTOrRMFEEMX4lquAPcgLxZKzQNAy8zUw/oBpnrep52Hmx7VfYFfCpAP7OxAL\nsA4mdKq1tx2e0g9so+5WeAa3yiKCvqkE6QJQXgk+WQ998aQg133HOUOqa1JKaU0k\nJK6fVYnJ74L7b6OWQDbehu0SBlAAypOJzkO4WysKOGiUCrrcgol2LmTImzCoTZS3\nPUUV0Rh2iI3v5t07vUfr5o415Em5YFwoPRhq3WH6hmP7wd9ducaFNl9Q/XyYQmPK\nG1F3RQNwtSy6aeAUajw6HTWd+FlFA6oA9LLaVxCoTxlejLB8IrYo3y2PGxPAXNl3\nqodsXWk/I/Jm/nus+RLVGCoJLl+i+zzEF0WG20+rfb0cNPjzuzgWuYY2PTBu78Ib\nizaXLv23fPLmxxUwHQgcCc4RgbmBAwhLWTsGETRLbDSWwBZnkv6PnMVlyrzs47jf\nr+vFYIxdiz8VvJe+sQ7hSrkzVjCluKIXhWT3bPtOkq4fepTnZmGi3qXRCg5cacd8\ni+KLaGtsHIsNyGOGfi55S5ZiSMo7kbeUxfM6xFjfhWuj3jDmMYfYQgBSmP2CNcEU\nTWmx7zJiaO3Me1q3sFG8Ti0CAwEAAQ==\n-----END PUBLIC KEY-----\n"
	},
	"endpoints": {
		"void:sparqlEndpoint": "https://mypod.store/alice/sparql",
		"proxyUrl": "https://mypod.store/alice/proxy"
	},
	"url": "https://mypod.store/alice/data/profiles/63c143b75ea9720d1b484a39"
}

Some Solid predicates are still missing (#122)

Authentication

Solid-OIDC

⚠️ Will be available in ActivityPods 2.0

In v2.0, we partly support authentication through Solid-OIDC. This is detailed in #121.

We do not support yet DPoP to request resources, but it will be implemented as soon as possible. In the meanwhile, the ActivityPub-defined Proxy endpoint should be used to request remote servers.

HTTP Signature

We support HTTP signature for server-to-server authentication. This is the standard used by ActivityPub.

There is now a proposal to integrate HTTP signature in the Solid protocol.

WebID-TLS

Considering WebID-TLS authentication mechanism, used before Solid-OIDC, is now only an option, we will not implement it.

Authorization

Web Access Control

We support the full WAC specification.

Access Control Policy

We do not support yet the ACP specification.

Application interoperability

⚠️ Will be available in ActivityPods 2.0

Solid Application Interoperability is a complex specification which is not yet complete. We’ve implemented everything we can at the moment and are waiting to see how it evolves before implementing the remaining parts.

We’re following the proposed ontology closely. On the other hand, application registration is done via ActivityPub, as this was the simplest method for us (applications are ActivityPub actors). We’ve also decided not to use ShapeTrees for the time being, as we don’t think they add anything to our triplestore-based architecture: instead, applications just declare the classes they want to manage.

What we implement
  • Applications declare their needs through AccessNeedGroups and AccessNeeds, which are displayed on an authorization screen.

  • Before registration, AccessGrants and DataGrants are created on the user’s Pod.
  • The ApplicationRegistration resource is created on the user’s Pod and sent to the application through a Create activity.

  • If the ApplicationRegistration is correct, it is saved on the application instance, as well as the corresponding grants. It returns an Accept activity.

  • Whenever the user connects again to the application, we check that the AccessNeeds haven’t changed. If needed, we show an authorization screen again and ApplicationRegistration is updated (with a Update activity).

  • If the user wants to uninstall the application, we delete the ApplicationRegistration (and corresponding grants) and send a Delete activity to the application.

What we don’t implement yet
  • Authorization flow is handled using ActivityPub. The application is an ActivityPub actor.
  • We only handle registration with Applications, not with other SocialAgents (we continue to use WAC permissions for the latter)

  • Pods don’t declare an AuthorizationAgent. It is handled internally.
  • Pods don’t declare a DataRegistry. This registry is only used to list ShapeTrees. TypeIndex can be used instead.

  • Applications don’t declare AccessDescription for the time being (we can deduce the accesses requested, and later it may be used to justify access to certain resources).

  • Pods only create AccessGrants and DataGrants, not AccessAuthorizations and DataAuthorizations. Grants can be shared with the registered application, while Authorizations cannot. The only difference between them is a grantedWith predicate in AccessAuthorizations that indicates which app was used to manage authorizations (but we manage that internally anyway).

  • Pods don’t declare RegistrySet, ApplicationRegistry, AuthorizationRegistry as they are not visible from the outside. We just read ApplicationRegistrations, AccessGrants and DataGrants in their dedicated containers.

Type Indexes

👷 To be implemented (#1171)

Linked Data Notifications

Linked Data Notifications, standardized in 2017, were the basis of the ActivityPub protocol (standardized in 2018). LDN defines only inboxes, while ActivityPub defines a full communication protocol, with inboxes and outboxes.

Since we implement the full ActivityPub protocol, we haven’t needed to implement the more lightweight LDN protocol, but it could be added in the future.

Solid Notifications

⚠️ Will be available in ActivityPods 2.0

Thanks to the [Solid Notifications Protocol](https://solid.github.io/notifications/protocol, you can listen to LDP resources, LDP containers or ActivityStreams collections.

We support discovering the notification subscription services through the storage description resource. This can be found by doing a HEAD request on any resource in your pod and looking for the Link header with the http://www.w3.org/ns/solid/terms#storageDescription relationship.

This leads to the /.well-known/solid endpoint which includes links to available subscription services.

  {
    "@context": { "notify":"http://www.w3.org/ns/solid/notifications#" },
    "@id": "http://localhost:3000/.well-known/solid",
    "@type":"http://www.w3.org/ns/pim/space#Storage",
    "notify:subscription": [
      "http://localhost:3000/.notifications/WebSocketChannel2023",
      "http://localhost:3000/.notifications/WebhookChannel2023"
    ]
  }
Webhooks subscription

To subscribe to the http://localhost:3000/foo resource using WebSockets, you use an authenticated POST request to send the following JSON-LD document to the server, at http://localhost:3000/.notifications/WebhookChannel2023/:

{
  "@context": [ "https://www.w3.org/ns/solid/notification/v1" ],
  "type": "http://www.w3.org/ns/solid/notifications#WebhookChannel2023",
  "topic": "http://localhost:3000/foo",
  "sendTo": "https://example.com/webhook"
}

The sendTo predicate is the Webhook URL of your server, the URL to which you want the notifications to be sent.

Notification types

Just like the Community Solid Server, we support five different notification types that the client can receive. The format of the notification can slightly change depending on the type.

  • Create: When the resource is created.
  • Update: When the existing resource is changed.
  • Delete: When the resource is deleted. Does not have a state field.

Additionally, when listening to a LDP container or an ActivityStreams collection, there are two extra notifications that are sent out when the contents of the container or collection change. For these notifications, the object field references the resource that was added or removed, while the new target field references the container or collection itself.

  • Add: When a new resource is added to the container or collection.
  • Remove: When a resource is removed from the container or collection.