Manage Access to Data (WAC)#

With Web Access Control (WAC), Access Control Lists determine the access to Resources stored in Solid Pods.

Access Control List#

A Resource’s Access Control Lists (ACLs) determine the access to that Resource. An ACL entry can specify the following Access Modes :

Access (i.e., an ACL entry) can be granted to individual agents, to groups, or even to everyone.

For a Resource, you can define:

  • a Resource-specific ACL that applies only to that Resource, and

  • an inheritable ACL that applies to the Resource’s children as a default/fallback ACL if they don’t specify their own Resource-specific ACL.

That is, if a Resource has a Resource-specific ACL, that ACL applies to that Resource and only to that Resource. However, if the Resource-specific ACL does not exist, the Resource’s Container’s inheritable ACL (or if that is unset, then that of its Container’s Container, etc.) acts as the Resource’s fallback ACL. As such, the ACL for a Resource may be defined in a separate Resource, and retrieving a Resource with its ACL may result in extra HTTP requests being sent.

Read Access Information for a Resource#

Tip

The solid-client library also provides universal access control APIs that can be used with either Manage Access to Data (ACP) or WAC.

When possible, use the universal access control APIs instead of the ACP-specific APIs or WAC-specific APIs. For situations that require ACP-specific or WAC-specific APIs, see Mechanism-Specific Access Control APIs.

Using the mechanism-specific APIs, it is possible for you to define an access model that is incompatible with the universal access APIs and, therefore, can only be managed with the mechanism-specific APIs.

To retrieve the ACL for a resource in addition to the Resource itself, use the getSolidDatasetWithAcl function. The returned value includes the Resource data, the ResourceInfo (i.e., metadata), and the ACL.

Note

The getSolidDatasetWithAcl function may result in many extra HTTP requests being sent.

Read Public Access#

From a SolidDataset that has an ACL attached, you can use getPublicAccess to retrieve the access granted to the public in general, regardless of whether they are authenticated or not.

import {
  getSolidDatasetWithAcl,
  getPublicAccess,
} from "@inrupt/solid-client";

const myDatasetWithAcl = await getSolidDatasetWithAcl("https://example.com");
const publicAccess = getPublicAccess(myDatasetWithAcl);

// => an object like
//    { read: true, append: false, write: false, control: true }
//    or null if the ACL is not accessible to the current user.

Reading Agent Access#

From a SolidDataset that has an ACL attached, you can use:

  • getAgentAccess to retrieve the access granted to a specific agent:

    import {
      getSolidDatasetWithAcl,
      getAgentAccess,
    } from "@inrupt/solid-client";
    
    const webId = "https://example.com/profile#webid";
    const myDatasetWithAcl = await getSolidDatasetWithAcl("https://example.com");
    const agentAccess = getAgentAccess(myDatasetWithAcl, webId);
    
    // => an object like
    //    { read: true, append: false, write: false, control: true }
    //    or null if the ACL is not accessible to the given user.
    
  • getAgentAccessAll to retrieve access information for all agents that have access:

    import {
      getSolidDatasetWithAcl,
      getAgentAccessAll,
    } from "@inrupt/solid-client";
    
    const myDatasetWithAcl = await getSolidDatasetWithAcl("https://example.com");
    const accessByAgent = getAgentAccessAll(myDatasetWithAcl);
    
    // => an object like
    //    {
    //      "https://example.com/profile#webid":
    //        { read: true, append: false, write: false, control: true },
    //      "https://example.com/other-profile#webid":
    //        { read: true, append: false, write: false, control: false },
    //    }
    

Reading Group Access#

From a SolidDataset that has an ACL attached, you can use:

  • getGroupAccess to retrieve the access granted to a specific group:

    import {
      getSolidDatasetWithAcl,
      getGroupAccess,
    } from "@inrupt/solid-client";
    
    const groupUrl = "https://example.com/address-book#friends";
    const myDatasetWithAcl = await getSolidDatasetWithAcl("https://example.com");
    const groupAccess = getGroupAccess(myDatasetWithAcl, groupUrl);
    
    // => an object like
    //    { read: true, append: false, write: false, control: true }
    //    or null if the ACL is not accessible to the given group.
    
  • getGroupAccessAll to retrieve access information for all groups that have access:

    import {
      getSolidDatasetWithAcl,
      getGroupAccessAll,
    } from "@inrupt/solid-client";
    
    const myDatasetWithAcl = await getSolidDatasetWithAcl("https://example.com");
    const accessByGroup = getGroupAccessAll(myDatasetWithAcl);
    
    // => an object like
    //    {
    //      "https://example.com/address-book#family":
    //        { read: true, append: false, write: false, control: true },
    //      "https://example.com/address-book#friends":
    //        { read: true, append: false, write: false, control: false },
    //    }
    

Change Access to a Resource#

Tip

The solid-client library also provides universal access control APIs that can be used with either Manage Access to Data (ACP) or WAC.

When possible, use the universal access control APIs instead of the ACP-specific APIs or WAC-specific APIs. For situations that require ACP-specific or WAC-specific APIs, see Mechanism-Specific Access Control APIs.

Using the mechanism-specific APIs, it is possible for you to define an access model that is incompatible with the universal access APIs and, therefore, can only be managed with the mechanism-specific APIs.

The following outlines the steps for modifying a Resource-specific ACL. If the Resource does not currently have a Resource-specific ACL (i.e., the Resource uses the fallback ACL inherited from its Container (or its Container’s Container, etc.)), the outline includes creating a Resource-specific ACL, overriding that fallback ACL.

Important

You must have Control Access on the Resource to modify its ACL.

To modify access to a Resource:

  1. Use getSolidDatasetWithAcl to retrieve the Resource and its ACL.

  2. From the retrieved Resource, call getResourceACL to obtain its Resource-specific ACL. The function returns null if the Resource-specific ACL does not exist.

  3. If the Resource-specific ACL exists,

    1. You can create a modified ACL from the existing Resource-specific ACL.

    2. Ensure that the modified ACL includes at least one entry with Control Access.

    3. Save the modified ACL to the Pod.

  4. Otherwise, you can create a new Resource-specific ACL and save. Once you save the new Resource-specific ACL, this ACL overrides the inherited fallback ACL.

    1. To create a new ACL, you can use createAcl to create a new empty ACL.

    2. If you have access to the Resource’s fallback ACL, you can copy the currently applicable rules to the newly-initialised ACL.

    3. Ensure that the modified ACL includes at least one entry with Control Access.

    4. Save the modified ACL to the Pod.

The general process for changing access to a Resource is as follows:

import {
  getSolidDatasetWithAcl,
  hasResourceAcl,
  hasFallbackAcl,
  hasAccessibleAcl,
  createAcl,
  createAclFromFallbackAcl,
  getResourceAcl,
  setAgentResourceAccess,
  saveAclFor,
} from "@inrupt/solid-client";

// Fetch the SolidDataset and its associated ACLs, if available:
const myDatasetWithAcl = await getSolidDatasetWithAcl("https://example.com");

// Obtain the SolidDataset's own ACL, if available,
// or initialise a new one, if possible:
let resourceAcl;
if (!hasResourceAcl(myDatasetWithAcl)) {
  if (!hasAccessibleAcl(myDatasetWithAcl)) {
    throw new Error(
      "The current user does not have permission to change access rights to this Resource."
    );
  }
  if (!hasFallbackAcl(myDatasetWithAcl)) {
    throw new Error(
      "The current user does not have permission to see who currently has access to this Resource."
    );
    // Alternatively, initialise a new empty ACL as follows,
    // but be aware that if you do not give someone Control access,
    // **nobody will ever be able to change Access permissions in the future**:
    // resourceAcl = createAcl(myDatasetWithAcl);
  }
  resourceAcl = createAclFromFallbackAcl(myDatasetWithAcl);
} else {
  resourceAcl = getResourceAcl(myDatasetWithAcl);
}

// Give someone Control access to the given Resource:
const updatedAcl = setAgentResourceAccess(
  resourceAcl,
  "https://some.pod/profile#webId",
  { read: false, append: false, write: false, control: true }
);

// Now save the ACL:
await saveAclFor(myDatasetWithAcl, updatedAcl);

Set Public Access#

Given a Resource’s ACL obtained as specified in Change Access to a Resource, you can:

  • Use setPublicResourceAccess to grant Access Modes to everybody (whether logged in or not) for the Resource itself:

    import {
      setPublicResourceAccess,
    } from "@inrupt/solid-client";
    
    const resourceAcl = /* Obtained previously in the section "Change Access to a Resource" */;
    
    const updatedAcl = setPublicResourceAccess(
      resourceAcl,
      { read: true, append: true, write: false, control: false },
    );
    
    // `updatedAcl` can now be saved back to the Pod
    // using `saveAclFor()`.
    
  • Use setPublicDefaultAccess to grant Access Modes to everybody (whether logged in or not) for the Resource’s children if the Resource is a Container:

    import {
      setPublicDefaultAccess,
    } from "@inrupt/solid-client";
    
    const resourceAcl = /* Obtained previously in the section "Change Access to a Resource" */;
    
    const updatedAcl = setPublicDefaultAccess(
      resourceAcl,
      { read: true, append: true, write: false, control: false },
    );
    
    // `updatedAcl` can now be saved back to the Pod
    // using `saveAclFor()`.
    

Set Agent Access#

Given a Resource’s ACL obtained as specified in Change Access to a Resource, you can:

  • Use setAgentResourceAccess to grant Access Modes to an Agent for the Resource itself:

    import {
      setAgentResourceAccess,
    } from "@inrupt/solid-client";
    
    const resourceAcl = /* Obtained previously in the section "Change Access to a Resource" */;
    const webId = "https://example.com/profile#webid";
    
    const updatedAcl = setAgentResourceAccess(
      resourceAcl,
      webId,
      { read: true, append: true, write: false, control: false },
    );
    
    // `updatedAcl` can now be saved back to the Pod
    // using `saveAclFor()`.
    
  • Use setAgentDefaultAccess to grant Access Modes to an Agent for the Resource’s children if the Resource is a Container:

    import {
      setAgentDefaultAccess,
    } from "@inrupt/solid-client";
    
    const resourceAcl = /* Obtained previously in the section "Change Access to a Resource" */;
    const webId = "https://example.com/profile#webid";
    
    const updatedAcl = setAgentDefaultAccess(
      resourceAcl,
      webId,
      { read: true, append: true, write: false, control: false },
    );
    
    // `updatedAcl` can now be saved back to the Pod
    // using `saveAclFor()`.