WebACL

Web Access Control for Solid

Based on work by Tim Berners-Lee (2009) and the W3C Solid Community Group

What is WebACL?

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"

How It Works

  1. Every resource may have an associated .acl file containing authorization rules in RDF (Turtle or JSON-LD)
  2. Each authorization specifies an agent (who), access mode (what), and target resource (which)
  3. The server authenticates the requesting agent via WebID (e.g., Solid-OIDC)
  4. The server locates the effective ACL—the resource's own .acl, or the nearest ancestor container's ACL with acl:default
  5. Access is granted only if a matching authorization exists for the agent, mode, and resource

The .acl File

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.

Turtle format (canonical)

@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.

JSON-LD format (equivalent)

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" } ]
  }
]

Access Modes

acl:Read

View resource contents. Maps to HTTP GET, HEAD.

acl:Write

Create, modify, delete resources. Maps to PUT, POST, PATCH, DELETE. Implies Append.

acl:Append

Add data without removing existing data. Maps to POST and INSERT-only PATCH.

acl:Control

Read and modify the ACL resource itself. The meta-permission.

Access Subjects

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)

Directories

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" }
  ]
}

Inheritance

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.

ACL Ontology

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" }
  }
}

Common Patterns

Owner-only resource

{
  "@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" }
  ]
}

Public read, owner write

[
  {
    "@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" } ]
  }
]

Append-only inbox

[
  {
    "@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" } ]
  }
]

Group access

{
  "@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" }
  ]
}

Ecosystem

Specifications

Server Implementations

Libraries & SDKs

Tools

Learning Resources

W3C Solid Community Group

WebACL 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.

SKILL.md

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.