POST request not uploading file to the server

Viewed 715

I've been stuck with this problem for 3 days. I'm using React.js on the frontend with axios and want to upload the file to the server. There is an API endpoint which is a post endpoint something like this.

POST- https://88.66.123.122:20000/b1s/v1/Attachments2

This endpoint basically uploads the files to the server file system with the successful response that has 201 status. The response is successfully fine when I test the endpoint with the Desktop client Postman and the code snippet generated by this tool is this.

Postman Snippet

But I want to achieve this thing in browser UI. So I'm using React.js for this.

This endpoint also needs an authorization cookie in the request header to make sure the user is authenticated. So In the UI, I created a login button that basically sends a post request with a hardcoded credentials to the login endpoint and giving me a successful response with a session id.

I'm saving the session id in the browser as a cookie for the upload file but when I'm sending the cookie with the request, I'm getting the following response in the browser

Refused to set unsafe header "Cookie"

and the response I'm getting back with the following JSON.

POST https://88.66.123.122:20000/b1s/v1/Attachments2 [401 (Unauthorized)]

{
   "error" : {
      "code" : 301,
      "message" : {
         "lang" : "en-us",
         "value" : "Invalid session."
      }
   }
}

I don't know How I can solve this problem? You can see the GIF.

Code:

import React from 'react';
import axios from 'axios';

const URL_LOGIN = `${process.env.REACT_APP_SERVER}Login`;
const COMPANY_DB = process.env.REACT_APP_DB;
const URL_ATTACHMENT = `${process.env.REACT_APP_SERVER}Attachments2`;
const CREDENTIALS = {
  UserName: process.env.REACT_APP_USERNAME,
  Password: process.env.REACT_APP_PASSWORD,
  CompanyDB: COMPANY_DB
};


function App() {
  const [isLogin, setIsLogin] = React.useState(false);
  const [selected, setSelected] = React.useState(null);

  function onClick() {
    setIsLogin(true);
    axios
      .post(URL_LOGIN, CREDENTIALS)
      .then(function (response) {
        setIsLogin(false);
        console.log(response.data);
      })
      .catch(function (err) {
        setIsLogin(false);
        console.log(err);
      });
  }

  // onUpload
  function handleUpload(event) {
    console.log('File set', event.target.files[0]);
    setSelected(event.target.files[0]);
  }

  function uploadSubmit() {
    const formData = new FormData();
    formData.append('files', selected, selected?.name);

    axios
      .post(URL_ATTACHMENT, formData)
      .then(function (response) {
        console.log('response', response);
      })
      .catch(function (err) {
        console.log('err', err);
      });
  }

  return (
    <div>
      <div>
        <button type="button" onClick={onClick} disabled={isLogin}>
          Login Create Cookie
        </button>
      </div>

      <hr />

      <div>
        <div>
          <input type="file" onChange={handleUpload} />
        </div>
        <button type="button" onClick={uploadSubmit}>
          Upload File
        </button>
      </div>
    </div>
  );
}

export default App;
3 Answers

The cookies are managed by the server, not the client. In your case, you are using a cookie with HttpOnly flag. The client side scripting will not allow you to read the value of Cookies as it is a security threat.

In your nodejs application, the server must be sending a Cookie in response. The server must be doing something like this:

// nodejs (express)
res.cookie('cookieKey', "value", { maxAge: 900000, httpOnly: true });

notice the httpOnly flag, this flag prevents the cookie to be used by the client-side scripting.

Once you set the cookie in response to your NodeJs (Express) request, your browser should automatically start sending the Cookie with each of your requests.

If the request is cross-origin be sure to add withCredentials: true as a header in the axios request

After successfully getting the cookie/token from the server, pass the token in the header. (depends on how you are securing your API endpoint.)

axios
      .post(URL_ATTACHMENT, formData, { headers : { header : token }})
      .then(function (response) {
        console.log('response', response);
      })
      .catch(function (err) {
        console.log('err', err);
      });
Related