Requesting access as ESS authenticated application

I’m trying to implement authentication for ESS using Statically Registered Client Credentials and I’m following Authenticate (Node.js: Single-User App) — Inrupt JavaScript Client Libraries for that, but I feel like I’m missing something.
I’ve registered my app using the Inrupt Application Registration but how could I now as authenticated application request access to a user’s resource?
Maybe I’m overlooking something in the documentation, but that step is still unclear to me.

I also found universalAccess.getAgentAccess at Access Policies: Universal API — Inrupt JavaScript Client Libraries but that takes a webId of the agent, and if I understand it correctly, static applications work with a client id and secret.

Any help is appreciated :slight_smile:

Hello @smessie, and thanks for reaching out!

There are two different aspects to what you are trying to do: authentication, and access request. There are several ways to do authentication, and it looks like you found one fitting your use case, which is good: once authenticated, you can act as an agent having an identity in the Solid ecosystem, which is a mandatory first step to be given access to a resource.

Then, there are also different ways to being granted access to a resource by its owner. One (simplistic) way is to prompt the owner asking them to give you the appropriate access if they are the one using your application. They may go to a third-party app allowing such operation, such as PodBrowser. Another way, which also relies on the resource owner being present, is to rely on access requests and access grants, as described in Access Requests and Grants — Inrupt JavaScript Client Libraries.

There is currently no asynchronous mechanism that I know of to send an access request to an arbitrary person for them to grant in the future, but that’s a legitimate use case and we plan on working on it in the future.

Does this help answering your question?

1 Like

Hi @zwifi, thanks for replying!

I think I’ve found the way to go. I overlooked that I could get the application’s WebID using session.info.webId after using login, which I then can pass along to universalAccess.setAgentAccess.

I think that should work, but I can’t try yet because my newly created ESS POD https://id.inrupt.com/ieben gives 404’s resulting in not letting me create or thus give access to resources. I’ve already contacted Inrupt support so I hope I can resolve that soon so I can test if my thoughts above work.

Just to make sure we’re talking about the same thing, https://id.inrupt.com/ieben is a WebID, not a Pod. If you’ve created a user account directly at https://login.inrupt.com/, you’ll want to go to https://start.inrupt.com: this will provision the profile document associated to your WebID, as well as a Pod of which you’ll be owner.

Does this capture how you created the account in the first place, and does the proposed fix resolve the issue?

Aha thanks @zwifi ! Didn’t know about that.

Now I have my WebID https://id.inrupt.com/ieben and my profile document is at https://storage.inrupt.com/315d5aed-fb98-4501-95b3-4f8118e87a7a/profile, that would thus mean that all my documents are stored under https://storage.inrupt.com/315d5aed-fb98-4501-95b3-4f8118e87a7a/ which is then my podBase, correct?

That’s correct! Note that your WebID profile document is available when looking up your WebID (https://id.inrupt.com/ieben), and that this profile links to https://storage.inrupt.com/315d5aed-fb98-4501-95b3-4f8118e87a7a/profile, which is an extended, read/write profile hosted as a Solid Resource (it isn’t the case of the WebID profile). And you’re absolutely right, https://storage.inrupt.com/315d5aed-fb98-4501-95b3-4f8118e87a7a/ is the root of your Pod, which is also linked in your WebID profile.

1 Like

Great, thanks! This seems to work, however I still get following CORS error, aren’t we just supposed to send it with credentials or is something else wrong?

Access to fetch at 'https://id.inrupt.com/ieben' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is 'false' which must be 'true' when the request's credentials mode is 'include'.

Fetcher: <https://id.inrupt.com/ieben> Non-HTTP fetch exception: TypeError: Failed to fetch

Fetcher: CORS: RETRYING with NO CREDENTIALS for <https://id.inrupt.com/ieben>

When it then retries without credentials, it works to retrieve the profile resource.

And then something else. I’m using ember-solid which uses RDFlib.js under the hood, to create and update resources. This works just fine with CSS, but with ESS this doesn’t work, but I cannot find why. ember-solid uses the UpdateManager.update function from RDFlib. I’ve already dived into the source code but I cannot find if it would be a problem with ember-solid, or RDFlib or something else.
Any help would be appreciated!

1 Like

Correct, the WebID is a public resource and should not be requested with credentials.

Thanks, however my second question from above is actually related to the first one it seems.
When I try to request a private resource, I also get that CORS error.
E.g. https://storage.inrupt.com/315d5aed-fb98-4501-95b3-4f8118e87a7a/private/tests/my-products.ttl the (the file exists in my pod but is private)

If I use mashlib to try to edit/view that file, I get the same CORS error in the console and I cannot fetch that file.
https://solidos.github.io/mashlib/dist/browse.html?uri=https%3A%2F%2Fstorage.inrupt.com%2F315d5aed-fb98-4501-95b3-4f8118e87a7a%2Fprivate%2Ftests%2Fmy-products.ttl
I’m logged in with my Inrupt POD when trying this.

Did something change to how we should fetch a resource?

We debugged a bit and discovered that with https://penny.vincenttunru.com/ it works to retrieve the private resource.
When we look at the request being sent we can see a subtile difference in the headers of the requests.
On that last site, the following headers are additionally sent: sec-fetch-dest, sec-fetch-mode and sec-fetch-site. However, when I do copy request as fetch in chrome and resend the request via the browser console, it automatically removes the headers and the request is denied with the CORS error again.
In my application, those headers are lacking as well in the request for the private resource.
I thus suppose that those lacking headers are the cause of the CORS error but my question is if anyone would know how to add these headers? I can’t seem to find anything useful online about it.

CORS should be working as expected in ESS 2.0, and shouldn’t be being influenced by the sec-* headers (which aren’t actually settable by user code, they’re controlled by the browser).

As for Mashlib, the reason it’s even sending credentials in the first place seems odd, and there’s a comment about a 2014 bug regarding wildcard CORS (which ESS PodSpaces will set) and credentials.

The Inrupt SDKs should not be setting credentials to include, if they are, then this would be a bug (we did briefly have a “useTempEssCookie” thing, but we’ve completely removed that from the SDK as of earlier this year, as it wasn’t a standard feature).

Some more reading on this is here: Using the Fetch API - Web APIs | MDN

(Also, Mashlib appears to be using XMLHttpRequest instead of Fetch, which can result in differences being present)

Further, you might be having issues with ember-solid because:
a) it uses an outdated version of the SDK (1.11.7, latest is 1.12.2), the very next version, 1.11.8 actually is the one where we removed the ess cookie thing.
b) it doesn’t correctly follow predicates for where pods are located, see: ember-solid/solid-auth.js at master · redpencilio/ember-solid · GitHub — this should be doing the algorithm to find all pim:storage’s.

I would guess something is going wrong down that line of investigation maybe, though that’s as far as I can assist without having code to check / a minimal reproduction.

1 Like

Thanks for your reply. For your points a and b, I was already testing with a local version of ember-solid with SDK 1.12.2 and with a fix for the pods discovery, on the fix/ess-support branch, but looks like I forgot to mention that in my previous post. I’ve now combined those fixes and pushed on experimental/ess-support, which is released on NPM as ember-solid@0.3.2-beta.0.
I’ve also made a minimal reproduction of my app at GitHub - smessie/ember-solid-with-ess-test where you can see that it works just fine to create a new product and list them when you login in with a CSS POD, but does not work with a ESS POD.

1 Like

I think the pod URL code you now have is still perhaps not implemented correctly, but as for using authn, the only issue you’ll see is if something higher in your stack is setting credentials to include (you’d want credentials omit)

Okay, so after some time and debugging, I found out that for ESS, the request ends here in RDFlib rdflib.js/update-manager.ts at c14dfd57d5159ad5ac1ee2523cc7924968e24f53 · linkeddata/rdflib.js · GitHub while it does not for CSS.
This before the file exists in the POD, but also after I manually create the file in my ESS POD first.

I’ll now try to narrow down the problem further by checking the editable function, but if you would already have an idea, I would be happy to hear it!

Edit: editable returns at the last line: return undefined // We don't know (yet) as we haven't had a response (yet).

Okay so another update: I managed to get rid of the CORS errors with the hint you gave about credentials omit, I’ve added { withCredentials: false } to the rdflib Fetcher.load call in ember-solid because otherwise the initFetchOptions in the load uses Fetcher.setCredentials to set the credentials to include as default. Maybe we want to change that default to omit so things like mashlib work again as well, but at least it works now for ember-solid.

Though, updating the file still fails at return undefined // We don't know (yet) as we haven't had a response (yet) in editable.

The rdflib editable check is done after a request, it does not make any requests of its own. For http(s) requests, It fails if there is a wac-allow header forbidding editing, or if te response lacks both an accept-patch and an author-via header.

I’ve added print debug statements at each return statement in the function and it only reaches the last return statement. So not those of wac-allow. When I have a look at an earlier GET request to that resource, I see following response headers.
access-control-expose-headers: Content-Type,Link,Location,Accept-Patch,Accept-Post,Accept-Ranges,Vary,WWW-Authenticate,WAC-Allow,ETag,Strict-Transport-Security
wac-allow: user="read control write"
So I would think that those 2 wouldn’t be the problem?

What is the content of the Accept-Patch header?

I’m not sure if it is included separately now that I have a better look… It is included in access-control-expose-headers though