3

The issue

I need to do an authenticated download using javascript and fetch api. However, there is an automatic call to the backend of type document (which is request to fetch metadata), which does not get the necessary access token from the custom header (XCompanyAccessToken) to actually create the file to be downloaded.


The code

I am currently using the following code I found online:

function download(fileUrl) {
  let fileName;
  fetch(fileUrl, , {
        method: 'GET',
        headers: {
          'XCompanyAccesstoken' = '<access-token>',
          /* more headers, obsolete here */
        },
        mode: 'cors',
    })
  // the whole then blocks here only handle gziped files, but I left it here for completeness
  .then(response => {
            const contentEncodingHeader = response.headers?.get('Content-Encoding');
            if (contentEncodingHeader === 'gzip') {
                // kudos: https://stackoverflow.com/questions/40939380/how-to-get-file-name-from-content-disposition
                // there is no "build-in" way of parsing this, unfortunately.
                const contenDispositionHeader = response.headers?.get('Content-Disposition');
                const fileNameSplit = contenDispositionHeader?.split('filename=')?.[1];
                // removes double quotes at the beginning and end
                fileName = JSON.parse(fileNameSplit ?? '""');
                return response.blob();
            }
            return null;
        })
        .then(blobby => {
            if (blobby) {
                const objectUrl = window.URL.createObjectURL(blobby);

                anchor.href = objectUrl;
                anchor.download = fileName;
                anchor.click();

                window.URL.revokeObjectURL(objectUrl);
            }
        })
}

And those headers are correctly set in the call to the backend of type fetch, but missing in the call to the backend of type document.

In order to make the download work, the response header has the following headers exposed:

access-control-expose-headers: Content-Disposition, Content-Encoding

and the values are set correctly:

content-disposition: attachment; filename="2022-10-12_13-12_download.csv"
content-type: text/csv; charset=UTF-8

(note: the content-encoding header is not set)

However, as stated earlier, there are three calls to the backend done.

  1. the preflight (which runs fine)
  2. the metadata call (which needs the token, but does not get it)
  3. the fetch (which has the token):


I tried

to google a dozen different ways, all asking how can i add a custom header to the fetching of metadata for downloads?, but could not find anything on that matter.

Other than that, I noticed, that cookies are send to the backend when fetching the metadata:

So I tried to add the access token to the cookies programmatically, but the cookie is ignored because the cookie header does not include the programmatically set cookie.


Finally, the question

Is there any way, that I can make this work?

Is there any way, that I can send the custom XCompanyAccessToken header to the backend when the browser decides to initiate a call of type document to retrieve metadata?

Are any changes on the backend side needed for this?

Dominik Reinert
  • 1,075
  • 3
  • 12
  • 26
  • firstly please change 'XCompanyAccesstoken' = '', to 'XCompanyAccesstoken' : '', // more over I would suggest you try this hit via postman and see how it works out. the second thing is to check your Nginx/CDN are they sniffing out custom non-standard header – Ashish Yadav Oct 26 '22 at 09:40
  • Thanks for your answer @AshishYadav, but the browser is not sending the request tokens at all, are you sure that nginx or CDN could be interfering? How would that work? – Dominik Reinert Nov 02 '22 at 03:49
  • try making same request via postman/cmd see if that gives desired outcome – Ashish Yadav Nov 02 '22 at 10:09
  • @AshishYadav what exactly should that help with? – Dominik Reinert Nov 07 '22 at 09:36

1 Answers1

1

document requests are those that are initiated by the browser (Example, via a page navigation, user typing in a URL on the address bar, or in your case, opening a link via anchor.click();).

One cannot set custom headers to these requests as their lifecycle is under the control of the browser and not the client-side javascript code.

But what can be done is set appropriate cookies from javascript and they will be sent when the request is made. If the cookies you set in javascript is not being sent as expected, check if it is a cross-domain request. Also check the SameSite policies on the cookies to ensure the browser is allowed to send the cookies.

https://medium.com/swlh/7-keys-to-the-mystery-of-a-missing-cookie-fdf22b012f09 is a good article to help you debug missing cookies.

niranjan94
  • 754
  • 1
  • 8
  • 28
  • Thanks a lot for your answer. Unfortunately, it does not help me, as the article is behind a paywall and as state in my question, it is about a CORS request. – Dominik Reinert Oct 28 '22 at 07:02