plone.restapi icon indicating copy to clipboard operation
plone.restapi copied to clipboard

Downloading/streaming files from JS frontend

Open jaroel opened this issue 7 years ago • 13 comments

Hi, We're building our support system in react using plone.restapi. Now we need to stream large blobs from the backend to the end user. Say I've got a PDF on /Plone/orgs/projecta/specs/specs_v23_final4.pdf . How would I go about in linking to that file?

I cannot embed the users JWT token in the url, as the enduser will share that link. And please do not say "encode the file as base64/data uri". The file can be several GBs in size. :)

I could create a route /stream_blob, which acts as a proxy I guess?

jaroel avatar Oct 19 '16 12:10 jaroel

I think the question here is not specific about downloading files but how to handle links to the backend that need authentication.

The simplest way is as you propose to create a proxy in the frontend and to not have links to the backend at all. Although downloading directly from the backend would be more efficient.

The other option would be to redirect to the frontend's login page. This is something that could be done in the JWT PAS plugin.

buchi avatar Oct 21 '16 18:10 buchi

True dat. We're going to try the proxy stuff.

jaroel avatar Oct 22 '16 13:10 jaroel

@jaroel closing the ticket now. Feel free to re-open if you do not agree.

tisto avatar Nov 26 '16 01:11 tisto

Adding @sneridagh's comment from #452 here:

Impossible to retrieve private images and files from standard GET contents using the token auth

Given an standard GET content from a file or image, it returns a download property with the URL of the API server e.g.:

content-type: "image/jpeg",
"download": "https://server/the-image/@@images/image",
...

but accessing to the image by the browser itself throws a 401, since the resource should be accessed with the token header. You can workarround this by making the request via JS, but it feels highly cumbersome.

tisto avatar Nov 30 '17 11:11 tisto

@tisto @sneridagh

When an authenticated user makes requests to URLs like:

https://server/the-image/@@images/image

an auth_token cookie is sent. Why is this not enough to get a private image?

wesleybl avatar Sep 01 '22 12:09 wesleybl

If the API server is under the same URL, you can. In fact, I think it's the case with the latests additions to p.restapi. (I'll have to double check). But, you'll need to have the API server public too (and so the classic UI). The recommended way is to expose only the ++api++ traversal, as it has a lot of advantages and they are a lot of deployment scenarios where the first premise is not true.

Also, by using the proxy your app is only using own server resources and it's easy to manage and to work with, as they are all flattened to one URL (the Volto/NodeJS server one). Also, you'll be relying on two means of authentication, the token one (for RESTAPI calls) and another for images/files/any downloadable resource coming from the backend, being both have to be sync'd.

One could argue that the API calls (albeit the latest additions in matter of auth to p.restapi) also can be driven by a cookie, but it misses absolutely the point of the REST auth decoupling.

sneridagh avatar Sep 02 '22 17:09 sneridagh

If the API server is under the same URL, you can.

@sneridagh I found a situation where, even though the api and the Volto are in the URL, this is not possible. I made the following configuration:

  • I have an nginx that receives all requests.
  • If it has /++api++ in the URL, it redirects to Plone.
  • If it has @@download or @@images in the URL, it also redirects to Plone.
  • Other URLs are directed to Volto.

When we authenticate to Volto for the first time, two cookies are created. auth_token and __ac. In this situation, private images in the format:

https://server/the-image/@@images/image

can be accessed by the authenticated user. As stated above, the request to this image will be made directly in Plone.

If I close the browser, without clicking in Volto exit button, and open the browser again, the auth_token cookie will still be in the browser and the __ac cookie will no longer be. That is, the auth_token cookie has a time validity and the __ac cookie is valid only until we close the browser.

In this situation, we are still authenticated since we still have the auth_token cookie. However, we are no longer able to access images with the above format. That is, we were only able to access it before, because of the __ac cookie.

To avoid this situation, I redirected the @@download and @@images URLs to Volto. So now the user can access them, even when we only have the auth_token cookie.

So my question is. Why can't we access them, going straight to Plone, when we only have the auth_token cookie?

wesleybl avatar Sep 03 '22 13:09 wesleybl

@wesleybl As you describe, the presence of the old __ac cookie is the reason why now the API request might get authenticated using a cookie, and these are the changes I was mentioning (implemented by Ross Patterson).

The purpose of auth_token is to be used only but Volto. It was never intended to merge both or that Volto authenticates through this cookie (or through __ac). The auth_token is a mean to persist the user token through reloads/sessions whenever is required, not to auth with a cookie. This does not mean that it does work (under some special circumstances, that were completely not intended). We never had the intention to merge them or get back to a cookie only solution for Volto, because as I said in my last comment it completely misses the point of the REST auth decoupling.

As said before, I'd try to stick to the recommended way of work with Volto, which I think it does work in every circumstance if used Volto alone and it's battle tested during the last 5 years.

sneridagh avatar Sep 03 '22 16:09 sneridagh

@sneridagh the fact is that requests to ++api++ "understand" the auth_token cookie and requests to other URLs do not. When I sent the @@images URL to Volto, I somehow managed to get the private image. So I'm assuming that Volto has extracted the token from the cookie and put it in the Authorization header. Would it be this?

wesleybl avatar Sep 03 '22 17:09 wesleybl

I see it here:

https://github.com/plone/volto/blob/f21c92ac1a9c83fa8143fb0ba7944d748d58d65d/src/helpers/Api/Api.js#L72

wesleybl avatar Sep 03 '22 17:09 wesleybl

the fact is that requests to ++api++ "understand" the auth_token cookie and requests to other URLs do not.

So it's not Plone that understands the cookie auth_token for ++api++ requests but Volto that adds the Authorization header to the request. Whereas URLs like @@images do not have the Authorization header in the request. Probably because the request is made by HTML. Now I'm starting to understand. There really isn't much to do, right?

wesleybl avatar Sep 03 '22 18:09 wesleybl

@rpatterson your PR #1303 solves the __ac and auth_token cookies out of sync problem that I described in https://github.com/plone/plone.restapi/issues/148#issuecomment-1236117123 ?

wesleybl avatar Sep 06 '22 21:09 wesleybl

There are lots of Volto sites, that presumably have no problem here, so I will remove the "blocker" tag (I am going through this list). Feel free to argue otherwise if you think this is a blocker that should hold up a final release or release candidate.

mauritsvanrees avatar Sep 29 '22 19:09 mauritsvanrees