Web Access Control for Solid
Web Access Control (WAC) is a decentralized, cross-domain access control system for Linked Data.
A server stores authorization rules in .acl files—RDF documents that describe
who can perform what operations on which resources. Agents are identified
by WebID URIs. Permissions cascade through container
hierarchies via inheritance.
WAC is the primary authorization mechanism in the
Solid Protocol. Every resource can have an associated
ACL resource, discoverable via a Link header with rel="acl".
Link: <https://alice.pod/docs/file1.acl>; rel="acl"
.acl file containing authorization rules in RDF (Turtle or JSON-LD).acl, or the nearest ancestor container's ACL with acl:default
An ACL file is an RDF document. Each acl:Authorization resource must have
all four components: a type, an access subject, an access mode, and an access target.
@prefix acl: <http://www.w3.org/ns/auth/acl#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
# Owner has full access
<#owner>
a acl:Authorization;
acl:agent <https://alice.pod/profile/card#me>;
acl:accessTo <./file1>;
acl:mode acl:Read, acl:Write, acl:Control.
# Public can read
<#public>
a acl:Authorization;
acl:agentClass foaf:Agent;
acl:accessTo <./file1>;
acl:mode acl:Read.
Since ACL files are RDF, they can be expressed in JSON-LD—making them accessible to web developers and AI agents that work natively with JSON. Multiple authorizations are expressed as a JSON array:
[
{
"@context": { "acl": "http://www.w3.org/ns/auth/acl#" },
"@id": "#owner",
"@type": "acl:Authorization",
"acl:agent": { "@id": "https://alice.pod/profile/card#me" },
"acl:accessTo": { "@id": "./file1" },
"acl:mode": [
{ "@id": "acl:Read" },
{ "@id": "acl:Write" },
{ "@id": "acl:Control" }
]
},
{
"@context": {
"acl": "http://www.w3.org/ns/auth/acl#",
"foaf": "http://xmlns.com/foaf/0.1/"
},
"@id": "#public",
"@type": "acl:Authorization",
"acl:agentClass": { "@id": "foaf:Agent" },
"acl:accessTo": { "@id": "./file1" },
"acl:mode": [ { "@id": "acl:Read" } ]
}
]
View resource contents. Maps to HTTP GET, HEAD.
Create, modify, delete resources. Maps to PUT, POST, PATCH, DELETE. Implies Append.
Add data without removing existing data. Maps to POST and INSERT-only PATCH.
Read and modify the ACL resource itself. The meta-permission.
| Predicate | Grants access to |
|---|---|
acl:agent |
A specific agent identified by WebID URI |
acl:agentGroup |
Members of a vcard:Group (external RDF document) |
acl:agentClass foaf:Agent |
Everyone (public access, including unauthenticated) |
acl:agentClass acl:AuthenticatedAgent |
Any authenticated agent (must have a WebID) |
acl:origin |
A specific web application origin (combined with agent) |
In Solid, directories are called containers. Their URIs end with /.
Each container can have a .acl file that controls access to the directory itself
and, via acl:default, to everything inside it.
| Resource | ACL file |
|---|---|
https://pod/docs/ (directory) |
https://pod/docs/.acl |
https://pod/docs/file1 (file) |
https://pod/docs/file1.acl |
https://pod/ (root directory) |
https://pod/.acl |
acl:Read on a directory lets an agent list its contents.
acl:Write lets an agent create and delete resources inside it.
Two scope predicates control what the ACL applies to:
| Predicate | Applies to |
|---|---|
acl:accessTo <./> |
The directory itself only |
acl:default <./> |
Files and subdirectories inside (that lack their own .acl) |
| Both together | The directory and all its contents |
These are independent. An authorization with only acl:default
does not apply to the directory itself. To cover both, include both predicates:
{
"@context": { "acl": "http://www.w3.org/ns/auth/acl#" },
"@id": "#owner",
"@type": "acl:Authorization",
"acl:agent": { "@id": "https://alice.pod/profile/card#me" },
"acl:accessTo": { "@id": "./" },
"acl:default": { "@id": "./" },
"acl:mode": [
{ "@id": "acl:Read" },
{ "@id": "acl:Write" },
{ "@id": "acl:Control" }
]
}
If a resource has no .acl file, the server walks up the container hierarchy
looking for the nearest ancestor ACL with acl:default. The root container's
ACL always exists.
https://alice.pod/
.acl ← root ACL (always exists)
profile/
card ← inherits from root .acl
card.acl ← own ACL overrides inheritance
public/
.acl ← container ACL with acl:default
photos/
vacation.jpg ← inherits from public/.acl
inbox/
.acl ← owner R/W, public Append
acl:accessTo applies to the resource itself.
acl:default applies to child resources that lack their own ACL.
These are independent—use both to cover a container and its children:
<#owner>
a acl:Authorization;
acl:agent <https://alice.pod/profile/card#me>;
acl:accessTo <./>; # this container
acl:default <./>; # inherited by children
acl:mode acl:Read, acl:Write, acl:Control.
The full ontology lives at http://www.w3.org/ns/auth/acl#. Here is the complete JSON-LD context for WebACL:
{
"@context": {
"acl": "http://www.w3.org/ns/auth/acl#",
"foaf": "http://xmlns.com/foaf/0.1/",
"vcard": "http://www.w3.org/2006/vcard/ns#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"Authorization": "acl:Authorization",
"Read": "acl:Read",
"Write": "acl:Write",
"Append": "acl:Append",
"Control": "acl:Control",
"accessTo": { "@id": "acl:accessTo", "@type": "@id" },
"default": { "@id": "acl:default", "@type": "@id" },
"agent": { "@id": "acl:agent", "@type": "@id" },
"agentClass": { "@id": "acl:agentClass", "@type": "@id" },
"agentGroup": { "@id": "acl:agentGroup", "@type": "@id" },
"mode": { "@id": "acl:mode", "@type": "@id", "@container": "@set" },
"origin": { "@id": "acl:origin", "@type": "@id" },
"accessControl": { "@id": "acl:accessControl", "@type": "@id" },
"AuthenticatedAgent": "acl:AuthenticatedAgent",
"Agent": "foaf:Agent",
"Group": "vcard:Group",
"hasMember": { "@id": "vcard:hasMember", "@type": "@id" }
}
}
{
"@context": { "acl": "http://www.w3.org/ns/auth/acl#" },
"@id": "#owner",
"@type": "acl:Authorization",
"acl:agent": { "@id": "https://you.pod/profile/card#me" },
"acl:accessTo": { "@id": "./private-file" },
"acl:mode": [
{ "@id": "acl:Read" },
{ "@id": "acl:Write" },
{ "@id": "acl:Control" }
]
}
[
{
"@context": { "acl": "http://www.w3.org/ns/auth/acl#" },
"@id": "#owner",
"@type": "acl:Authorization",
"acl:agent": { "@id": "https://you.pod/profile/card#me" },
"acl:accessTo": { "@id": "./resource" },
"acl:mode": [
{ "@id": "acl:Read" },
{ "@id": "acl:Write" },
{ "@id": "acl:Control" }
]
},
{
"@context": {
"acl": "http://www.w3.org/ns/auth/acl#",
"foaf": "http://xmlns.com/foaf/0.1/"
},
"@id": "#public",
"@type": "acl:Authorization",
"acl:agentClass": { "@id": "foaf:Agent" },
"acl:accessTo": { "@id": "./resource" },
"acl:mode": [ { "@id": "acl:Read" } ]
}
]
[
{
"@context": { "acl": "http://www.w3.org/ns/auth/acl#" },
"@id": "#owner",
"@type": "acl:Authorization",
"acl:agent": { "@id": "https://you.pod/profile/card#me" },
"acl:accessTo": { "@id": "./inbox/" },
"acl:default": { "@id": "./inbox/" },
"acl:mode": [
{ "@id": "acl:Read" },
{ "@id": "acl:Write" },
{ "@id": "acl:Control" }
]
},
{
"@context": { "acl": "http://www.w3.org/ns/auth/acl#" },
"@id": "#appendPublic",
"@type": "acl:Authorization",
"acl:agentClass": { "@id": "acl:AuthenticatedAgent" },
"acl:accessTo": { "@id": "./inbox/" },
"acl:default": { "@id": "./inbox/" },
"acl:mode": [ { "@id": "acl:Append" } ]
}
]
{
"@context": {
"acl": "http://www.w3.org/ns/auth/acl#"
},
"@id": "#teamAccess",
"@type": "acl:Authorization",
"acl:agentGroup": { "@id": "https://you.pod/groups#Engineering" },
"acl:accessTo": { "@id": "./shared-doc" },
"acl:mode": [
{ "@id": "acl:Read" },
{ "@id": "acl:Write" }
]
}
npx wchmod +r public ./resource) JavaScriptWebACL was originally proposed by Tim Berners-Lee in May 2009 as part of the W3C WebAccessControl work. The current specification (Version 1.0.0, 12 May 2024) is maintained by the W3C Solid Community Group, edited by Sarven Capadisli.
The specification mandates that Solid servers conform to either WAC or ACP (Access Control Policy). WAC is the more widely deployed mechanism; ACP offers greater expressivity for complex authorization scenarios.
The SKILL.md file provides a machine-readable implementation
guide for AI agents. It contains the complete JSON-LD context, authorization templates
for common patterns, and step-by-step instructions for generating valid .acl
files. An AI agent reading the SKILL.md can create WebACL resources programmatically.