Programmatically adjust ACL

What is the state of the art way of adjusting resource ACL nowadays? Are we still supposed to do low level operations with solid-auth-client, or is there some library that can do the following:

  1. Create new ACL for file.ttl, applying all permissions from parent ACL
  2. Add public append permission to file.ttl keeping everything else as is.

The more advanced & friendly I saw is @A_A

1 Like

You could use the libraries I’ve written for that, but keep in mind that they are not maintained (at least by me). Also the documentation isn’t that good and doesn’t reflect everything it can do iirc.

With solid-acl-parser you can read turtle strings into an object, modify it there with a simple API, and parse it back to turtle. Here’s a simple example (more documentation is here):

  // Parse the turtle to an AclDoc object which we can modify
  const parser = new AclParser({ aclUrl, fileUrl })
  const doc = await parser.turtleToAclDoc(turtleString)

  // Give the webId WRITE and CONTROL permissions
  doc.addRule([WRITE, CONTROL], webId)
// or in your case: doc.addRule(APPEND, Agents.PUBLIC)

  // Parse it back to turtle so we can store it in the pod
  const newTurtle = await parser.aclDocToTurtle(doc)

And if you also don’t want to manually fetch and save the acl file, I’ve written a wrapper solid-acl-utils which does that for you:

const aclApi = new AclApi(fetch, { autoSave: false }) // create one per acl file you want to modify
const acl = aclApi.loadFromFileUrl('')

acl.addRule([READ, WRITE], webId)
acl.addRule(READ, Agents.PUBLIC)

await acl.saveToPod()

These should make it rather simple to modify acl files, but as said above: I’m not going to maintain it, some things may be broken (though I’ve written tests for everything which came into my mind).


Even if not maintained, that’s a good starting point that helped me to understand & deal with Acl :+1::muscle::blush:

@aveltens how I use it for inbox for example


This looks really great and seams to do what I was looking for. Will give it a try.

Sad to hear, that you are not going to maintain it. Perhaps we should move it to the solid github org and ensure it is maintained by the community?

Looks like you are assuming a specific WebID structure here, which will bring problems to people with different URI structure.

You are right ,thxxs it just a copy/paste from an Acl file to start something but can be improved

1 Like

Sure, if somebody wants to keep it up to date and fix things when issues arise, I think it would be good to transfer it. I just don’t have the time to maintain this project, but I’d be happy if someone else forks it and takes care about it. I could also remove the solid-acl-parser on npm in favor of newer versions.

If this is done, it would probably also make sense to look if the databrowser could use it too. Currently it uses its own implementation iirc. Merging them to one would probably make sense

I also want to note, that my implementation is just one way of doing this. It parses the whole acl file into an object, modifies it, and parses it back. Another way would be to use a library to directly manipulate the turtle (e.g. with SPARQL statements)

Hey @A_A I had some time to try your lib and it is exactly what I was looking for. Thank you very much.

I am encountering just a small problem, perhaps you have an idea:

Couldn’t retrieve the acl location from the link header

This occurs, if I try to add an ACL to a container and there is now ACL except the root acl. If at least one of the parent containers has an ACL everything works fine. But the root ACL cannot be discovered somehow. Might as well be a bug in NSS, not sure.

With curl I can get a link to the ACL file from a Pod root:

▶ curl -s -I | grep Link:
Link: <.acl>; rel="acl", <.meta>; rel="describedBy", <>; rel="type"

But in the browser dev tools it is actually not to be found in the response of the OPTIONS request to the Pod root:

Link: <>; rel="service", <>; rel=""

Any ideas?


Apparently node-solid-server only sets the link header for GET but not for OPTIONS requests on the root. Here’s a simple script to reproduce it from the browser console when logged in to your pod:

fetch('/', { method: 'GET' }).then(res => console.log(res.headers.get('link')))
// <.acl>; rel="acl", <.meta>; rel="describedBy", <>; rel="type"
fetch('/', { method: 'OPTIONS' }).then(res => console.log(res.headers.get('link')))
// <>; rel="service", <>; rel=""

So I believe that it’s an issue of node-solid-server not adding rel="acl" to the link header.

EDIT: For HEAD it works fine. I’m not that familiar with the difference between HEAD and OPTIONS, so probably that should be used instead. If you know more about it just let me know and I’ll change it


I think a HEAD request would be correct as stated in Discovery of Auxiliary Resources

To discover the auxiliary resources directly associated with a given Solid resource, a Solid client MUST issue a HEAD or GET request to the target resource URL and inspect the Link headers in the response.

1 Like

I’ve updated it to use HEAD, can you try it with this version?


Awesome, it’s working :+1: Thanks a lot

1 Like

Hi @A_A sorry to bother you again. Your library has no capability to set a acl:default, or am I missing something?

You can use addDefaultRule(...) instead of addRule(...) to set the default.

Basically you can use everything defined in this map and all methods defined in this class. So if you don’t find a functionality in the documentation you can take a look there (and open a PR to add it to the documentation :))

1 Like

Thanks a lot, sorry I should not have missed that!

Hi @A_A, those libraries are great, as is your pod explorer.
is there any change you can add support for the origin predicate? this would allow trusted apps.

@A_A the issue is that if I create an ACL for a file inheriting (defaulting to) an origin predicate, the subject still points to the default location).

For example, this is what happens to the acl for after I load the default, amend it, and save it:

@prefix foaf: <>.

<#trusted-apps> a acl:Authorization;
    acl:agent </profile/card#me>;
    acl:accessTo <./foo.txt>;
    acl:mode acl:Control, acl:Read, acl:Write.
<> acl:origin <https://localhost>.
<#ControlReadWrite> a acl:Authorization;
    acl:agent </profile/card#me>, <>;
    acl:accessTo <./foo.txt>;
    acl:mode acl:Control, acl:Read, acl:Write.
<#Read-0> a acl:Authorization;
    acl:agent <>;
    acl:accessTo <./foo.txt>;
    acl:mode acl:Read.

You can see that the origin predicate still points to the parent.

I tried to bodge it by changing the structure just before saving it, but it does not have a setter, so I was wondering if you were inclined to add origin support.

You can take a look at the new inrupt lib too
Seems quite easy to deal with Acl