1

I get a plain API written in node.js such as this one:

const express = require('express')
const app = express();

app.post('/api/data', (req, res) => {
  res.status(200).json({
    data: [1,2,3,3,1,3,5,2,3,4,4,7]
  })
})

app.use('/gui', express.static('./gui'))

app.listen(8080, () => { console.log("OK") })

and a client javascript code accessing it with the fetch function, this way (e.g. ./gui/index.html):

fetch('/api/data', {
  method: 'post',
  headers: {
    'Accept': 'application/json', 'Content-Type': 'application/json'
  },
  body: JSON.stringify(json)
})
.then( res => { console.log(res })

It works fine, but now I want to put this API behind basic auth without changing the API code using nginx as man in the middle. The config file looks like:

server {
  listen 80;

  location / {
    auth_basic "Private Area";
    auth_basic_user_file .htpasswd; 

    proxy_pass http://localhost:8080;
    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
  }
}

Now, when I open the page in the browser, it asks for the auth infos, displays the HTML, but the AJAX accesses fail with a 401 error.

After checking it looks like the browser does not send the Authorization headers for the AJAX accesses.

The question is: is there a way to make the basic auth transparent to my API and GUI? I am doing something wrong?

Edit

It has been suggested that this question is a duplicate of Basic authentication with fetch?

I know how to set the headers explicitly to fetch. What I want here is the browser to set them implicitly when the application is behind basic auth, without any modification to my client code.

Antoine Trouve
  • 1,198
  • 10
  • 21
  • Possible duplicate of [Basic authentication with fetch?](https://stackoverflow.com/questions/43842793/basic-authentication-with-fetch) – Tomalak Jun 19 '18 at 05:56
  • 1
    Please read on https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch about the usage of the `credentials` option, it might already be what you need. – Tomalak Jun 19 '18 at 06:19
  • @Tomalak: thank you! Looks like the answer was RTFM. I had to specify `credentials: 'include'` in the options of the fetch. I can accept your answer if you write one. – Antoine Trouve Jun 19 '18 at 07:22
  • 1
    I wasn't sure if that would include basic auth headers, so I hesitated. It's fine if you write the answer, I'll upvote and everybody is happy. :) – Tomalak Jun 19 '18 at 07:23

1 Answers1

1

As kindly suggested by @Tomalak, and according to https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

By default, fetch won't send or receive any cookies from the server, resulting in unauthenticated requests if the site relies on maintaining a user session (to send cookies, the credentials init option must be set).

In other words, all I had to do is to modify my call to fetch this way:

fetch('/api/data', {
  credentials: 'include',
  method: 'post',
  headers: {
    'Accept': 'application/json', 'Content-Type': 'application/json'
  },
  body: JSON.stringify(json)
})
.then( res => { console.log(res) })

Note the credentials: 'include' in fetch options (it is possible to use same-origin instead of include for tighter security).

This way, the browser will implicitly set the auth headers if necessary.

Antoine Trouve
  • 1,198
  • 10
  • 21