rk_Tinelli
rk_Tinelli

Reputation: 89

Fetch in ReactJS with Basic Auth return 401 (Unauthorized). Preflight request doesn't pass access control check

I'm new at ReactJS but I'm trying to learn by myself now. I'm facing a problem when I try to add data do may Database, in my RestAPI with MongoDB, using fetch function on my web Application. When I click my button, it runs the following code:

SubmitClick(){
    //console.log('load Get User page'); //debug only

    fetch('http://localhost:4000/users/', {
      method: 'POST',
      headers: {
        'Authorization': 'Basic YWRtaW46c3VwZXJzZWNyZXQ=',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: '[email protected]',
        first_name: 'Wade',
        last_name: 'Wilson',
        personal_phone: '(11) 91111-2222',
        password: 'wolv3Rine'
      })
    })

    //this.props.history.push('/get'); //change page layout and URL
}

and I get the following message on my browser:

OPTIONS http://localhost:4000/users/ 401 (Unauthorized)

Failed to load http://localhost:4000/users/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Uncaught (in promise) TypeError: Failed to fetch

My RestAPI have Basic Auth, but i don't know what i'm supposed to insert in headers to have access. I got this 'Authorization': 'Basic YWRtaW46c3VwZXJzZWNyZXQ=', from Postman, when I configured the Authorization tab, and it was automatically added to the headers.

I'm using Google Chrome as my default browser.

My backend code is the following:

const express =     require('express');
const bodyParser =  require('body-parser');
const mongoose =    require('mongoose');
var basicAuth =     require('express-basic-auth')

const app = express();

mongoose.connect('mongodb://localhost/usersregs', { useMongoClient: true });
mongoose.Promise = global.Promise;

app.use(basicAuth({
    users: {
        'admin': 'supersecret',
        'adam': 'password1234',
        'eve': 'asdfghjkl'
    }
}))

app.use(bodyParser.json());

app.use(function(err, req, res, next){
    console.log(err);
    //res.status(450).send({err: err.message})
});

app.use(require('./routes/api'));  

app.listen(4000, function(){
    console.log('Now listening for request at port 4000');
}); 

Upvotes: 2

Views: 18902

Answers (2)

rob5408
rob5408

Reputation: 2982

It may not be the same problem as the OP, but I was able to get basic auth protected fetches working just by adding a credentials mode...

fetch(
    'http://example.com/api/endpoint',
    { credentials: "same-origin" }
)

See here: https://github.github.io/fetch/ under Request > Options

Upvotes: 6

Josh Siegl
Josh Siegl

Reputation: 735

You're trying to access port 4000 (your API, or backend) from port 3000 (Your client). This violates the Same-origin policy, even though you're clearly running both the client and the API from the same machine.

To get around this the easiest way is to just fire up your client from the same port as your API (port 4000) this should allow your host to see that you're trying to access resources from the same domain/port which won't force a preflight request.

If that's not possible you'll have to configure CORS for your API, and this question doesn't give any details about the backend so I can't instruct you on how to do that at the moment.

And of course this approach obviously won't work if you're running two separate servers in production, but that's probably outside of the scope of this question.

Upvotes: 2

Related Questions