Antoine Trouve
Antoine Trouve

Reputation: 1273

AJAX access to node API behind basic auth provided by proxy

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.

Upvotes: 1

Views: 387

Answers (1)

Antoine Trouve
Antoine Trouve

Reputation: 1273

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.

Upvotes: 1

Related Questions