sparq
Back to examples

Solid (user, app)-pair result sets

Live in your tabAccess-control decision precomputed · restriction is live
1 · One query, one Pod
This query runs for both (user, app) pairs, against the same four-document Pod. Edit it and re-run — only who is asking, from which app changes the rows that come back, because each pair’s authorized named-graph set is injected as a FROM NAMED restriction around whatever you type.

Access control still applies to your query: it is evaluated only over the named graphs the pair may read. Wrap patterns in GRAPH ?g { … } to read across the authorized documents — a query against the default graph alone returns nothing here, because a Pod’s data lives in its per-document named graphs (and that is the fail-closed default).

The Pod — one named graph per document:

Public profilepublic
…/profile/card
Name, role and public links — Alice's WebID profile document.
Shared calendarshared
…/calendar/shared
Events Alice shares with friends — book club, a hiking trip.
Private health dataprivate
…/health/records
Sensitive medical records — restricted to the owner via one trusted app.
Private notesprivate
…/notes/private
Personal notes — owner only, never shared with anyone.
2 · Pick two (user, app) pairs to compare
The session key is exactly sparq-solid’s Session { agent, client }. Pick a pair on each side, run, and watch the result sets diverge.
Pair A
Pair B
Alice (owner)·Her own dashboard
agent=https://alice.pod.example/profile/card#me · client=https://alice.example/dashboard/clientid
Authorized graphs (FROM NAMED)
  • …/profile/cardPublic profile
  • …/calendar/sharedShared calendar
  • …/notes/privatePrivate notes
1 graph invisible to this pair
  • Private health data(indistinguishable from absent)
Why these graphs? 3 WAC/ACP grants matched
WACPublic profileEveryone (public), any app
<#public> a acl:Authorization ;
  acl:accessTo  <profile/card> ;
  acl:agentClass foaf:Agent ;        # → auth:Public
  acl:mode      acl:Read .
WACShared calendarOwner + friend Bob, any app
<#shared> a acl:Authorization ;
  acl:accessTo <calendar/shared> ;
  acl:agent    <https://alice.pod.example/profile/card#me> , <https://bob.example/profile#me> ;
  acl:mode     acl:Read .
WACPrivate notesOwner only, any app
<#notes> a acl:Authorization ;
  acl:accessTo <notes/private> ;
  acl:agent    <https://alice.pod.example/profile/card#me> ;
  acl:mode     acl:Read .

Run the query to see what this pair gets back.

Stranger·Random app
agent=https://stranger.example/me#i · client=https://random-app.example/clientid
Authorized graphs (FROM NAMED)
  • …/profile/cardPublic profile
3 graphs invisible to this pair
  • Shared calendar(indistinguishable from absent)
  • Private health data(indistinguishable from absent)
  • Private notes(indistinguishable from absent)
Why these graphs? 1 WAC/ACP grant matched
WACPublic profileEveryone (public), any app
<#public> a acl:Authorization ;
  acl:accessTo  <profile/card> ;
  acl:agentClass foaf:Agent ;        # → auth:Public
  acl:mode      acl:Read .

Run the query to see what this pair gets back.

Run the same SPARQL over the same Pod for two different (user, app) pairs and watch the answers diverge — the engine restricts each query to exactly the named graphs that pair is authorized to read, with the WAC/ACP grant that produced each result shown alongside.

How enforcement works & full caveat

In Solid your data lives in your Pod, and the rules for who may read what can depend not just on who is asking but on which application they ask from. sparq models a Pod as one named graph per document and reduces enforcement to a dataset restriction: for a Session { agent, client }, sparq-solid materializes exactly the named graphs that pair may read, then evaluates the query only over that authorized set via a FROM NAMED clause (its rewrite_for path). The default is fail-closed: absence of a grant is denial, and a non-authorized graph is indistinguishable from absent — an ungranted requester gets the empty set, so the Pod looks empty to it.

What is real, and what is precomputed. The restriction you see is real: the Pod is loaded into the sparq wasm engine in your tab with its named graphs preserved, and the same query is rewritten per pair — the differing result sets are the real engine doing the real graph-level restriction. What is precomputed is the access-control decision (which named graphs each pair may read): the WAC/ACP materialization runs natively / at build time, not in the browser, and ships here as fixtures (the rules behind each are shown in the “why these graphs?” panels, so nothing is hidden).

Most importantly, sparq-solid is a research track, not a Solid-server cutover. Per the project house rule (issue #55), security-critical paths run through vetted TypeScript in the production Solid server; sparq-solid is at most an authorization oracle, never the sole gate. It does not authenticate — it answers a graph-set question for an already-resolved (WebID, client) Session. This demo shows the graph-level access-control capability and semantics, not a certified production Solid deployment.

The live SPARQL REPLsparq-solid on GitHub Issue #55 — scope & house rule