One-time / Short-span remote authenticated fetch?

This is a question related to [Solved] How to attest possession of a WebID (from arbitrary source)?, but with different focus.

In short: in JS, to fetch a Solid resource, how can I share the authenticated headers with a remote server, and let the remote server perform the request?

The usages are:

  1. The remote server can verify my identity (similar to the referenced post);
  2. The remote server can verify that I have permission to access the target resource.

What I understand so far

Based on my understanding, it looks like the following flow should work:

  1. The client obtains the authentication header to the target resource;
  2. The client sends a request to the relevant endpoint at the remote server, with payload/data containing the authentication header (and the link to the target resource if the remote server doesn’t know this beforehand);
  3. The remote server extracts the authentication header from payload/data, and attests WebID as stated in the linked post (through access-token-verifier);
  4. The remote server puts the header into HTTP request, and performs the request to the target resource.

If it indeed works based on the specification, how can I do Step 1 using any JS library (esp. @inrupt/solid-client-authn-browser)?
I know I can get a fetch object performing authenticated fetches, but there does not seem to be a function to obtain the relevant request header only?

1 Like

This is just after a quick thought but are you talking about verifiable credentials and/or access grants? I know ESS has a experimental features using them.

No. I’m talking about Solid-OIDC, I believe.
The assumption is that there has already been access rules set up, which should work correctly. But now I want to let an agent / remote server to access a particular resource that I have access to. There could be several reasons to do this, but the most appealing one to me is: the remote server knows that I have permission to a specific resource, as a means to verify my identity.

There could well be other ways to verify my identity, but this one has the benefit that the remote server does not need to know the list of all WebIDs they should permit – they will only know that “if this WebID is permitted or not”.

(Also added some additional information to the original post.)

1 Like

I believe right now the default with Solid-OIDC are the Authorization and DPoP headers, both of which are a dpop-bound jwt.

So the simplified workflow is a client prepares a JWT and sends it to the Authorization server which verifies the JWT and responds with an access token back to the client.

The client then takes this access token and attaches it in the Authorization header and looks like Authorization: DPoP access-token-string. The client then generates a DPoP token for the resource it wishes to access and sends it to the resource server as a DPoP header which looks like DPoP: resource-specific-jwt, who then validates the access token in the Authorization header and verifies the DPoP bound JWT for the specific resource.

Full DPoP diagram here

In theory your idea would work, as the resource server only needs to validate that the public key of the access token and the public key of the resource-specific DPoP token need to match. The remote server would simply have to perform that same check if I’m right, before forwarding the headers to the actual resource server.

A couple issues though could be in the claims, especially the issued at time and expiry time, if the request takes too long. Another issue could be a URL validation, if you create a token from client x and send from server y - the resource server may check for discrepancy against URLs.

I’m not sure if that answers your question, but in theory it could be as simple as taking and validating those headers from the initial request on the remote server, and then forwarding the request if it satisfies the conditions.

1 Like

Thanks for the comment with detailed explanation! Sorry I missed the reminder email.

Yes, that’s exactly my intuition. And thanks for the pointer to the details.
And the problem now (again) is how to perform this in JS? Do we/I need to implement this myself? Or are there any existing libraries to help?

In particular, we know Inrupt’s @inrupt/solid-client-authn-browser allows to perform authenticated fetch by providing such a function (wrapper). But there does not seem to be (a public function) to either:

  1. Compose the necessary Authorization and DPoP header; or
  2. Extract the two headers from the fetch request, and prevent this request being actually sent

The time won’t be an issue as I’d just need to (in real-time, if I may say this) verify the identity.
But the URL may be an issue, indeed. But I feel it can be circumvented as long as the remote server sends (inpersonates) the same URL as Origin (because we are relying on this for authentication, it should be fine for the client x to send its URL origin x to the remote server y).

And the problem now (again) is how to perform this in JS? Do we/I need to implement this myself? Or are there any existing libraries to help?

One rather comprehensive library for working with DPoP-bound JWTs in Javascript is probably the JOSE library. This allows you to perform many operations against JWTs and their supporting technologies. The only negatives here are the library is a bit low-level, which I prefer for debugging and flexibility but takes a bit more time, and the documentation can be rather confusing or cryptic.

The other option is the Access Token Verifier library for Solid . I have less experience with this one but it is used by the maintainers of the CommunitySolidServer, so it is probably relatively up to date. I cannot confirm if it will have all the functionality you may need.

Your last option is to do it yourself, which isn’t the hardest task since you aren’t making a flexible client but rather a single workflow which really only needs to store a keypair, headers, and meta information in a store (in-memory should be plenty). I wouldn’t recommend this but if you do decide on this route and need help with it, feel free to ask me.

But I feel it can be circumvented as long as the remote server sends (inpersonates) the same URL as Origin (because we are relying on this for authentication, it should be fine for the client x to send its URL origin x to the remote server y ).

You can also have two applications running on the same URI on different ports, and the web-facing URI would be the same, so this is probably not a concern. If it is remote I am less confident. You could always have a way for the server generating the keys to take the HTTP request being forwarded and handle the token generation itself, which may be easier.

One thing to potentially look at for attestation is the way the Android OS with Google support handles hardware-backed Key Attestation. I have used it very briefly myself, but it may give you some ideas on how to solidify(hehe) the remote attestation part more firmly.

Edit: I will mention that if I am right about what you are trying to do, you have to make the very strong security assumption that communication between these two servers is secure and both of them can be completely trusted, as forwarding both of those headers to a malicious server is a very bad idea.

Hi again. Thanks for the detailed explanations and pointers.

I took a read of them and also asked for help from local people familiar with Inrupt library, and he confirmed that the Inrupt library does have (private) functions for achieving that.
So I can simply copy-paste the two small functions, as the further called function is exported. (Or, as he pointed out, I can also do a post-install script to export them if demonstration is prioritized.)

Unfortunately that defeats the purpose of having two different components and the necessity of verifying the identity and permission.

Sorry but I don’t quite get this. From what I understand, the Authorization header does not contain the secret key of the App/client, and the DPoP header is generated from the Authorization header and the private key, and the request details. And the Solid server needs to verify both of them.

Thus, the pair of Authorization and DPoP header is meaningless for any further requests to a different resource.
So as long as I trust the network is secure (e.g. SSL/TLS), and the data to be retrieved by the DPoP header is not harmful/sensitive (and the Remote Service is semi-honest = may do other stuffs based on the retrieved data, but will do what it is expected to do, and won’t share it to a 4th party), I can safely share the Authorization and DPoP headers to the Remote Service.

Isn’t it the case?

(Maybe I’ll have to consult the figure you pointed to again, if this understanding is not correct…)

Sorry but I don’t quite get this. From what I understand, the Authorization header does not contain the secret key of the App/client, and the DPoP header is generated from the Authorization header and the private key, and the request details. And the Solid server needs to verify both of them.

This is all true, and is not the cause for concern.

Thus … So as long as I trust the network is secure (e.g. SSL/TLS), and the data to be retrieved by the DPoP header is not harmful/sensitive (and the Remote Service is semi-honest = may do other stuffs based on the retrieved data, but will do what it is expected to do, and won’t share it to a 4th party), I can safely share the Authorization and DPoP headers to the Remote Service.

I agree, and the terminology you may be referring to in security is “honest-but-curious”. There are a few different concerns with forwarding authn/authz headers regarding security, but all the assumptions you listed shouldn’t be a concern in those situations. I’m keeping the warning there for less security-minded users who may seek to do something similar and know less about what they are doing.