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

12,906

Solution 1

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.

Solution 2

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

Share:
12,906
rk_Tinelli
Author by

rk_Tinelli

Updated on July 10, 2022

Comments

  • rk_Tinelli
    rk_Tinelli almost 2 years

    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');
    }); 
    
    • Scott
      Scott over 6 years
    • HMR
      HMR over 6 years
      What is the url of the page in the browser? If it's not http://localhost/4000 (maybe because you're using webpack) then your API server should set a Access-Control-Allow-Origin header
    • rk_Tinelli
      rk_Tinelli over 6 years
      The url int he browser is http://localhost:3000/. I'm trying to figures it out how to set this Access-Control-Allow-Origin, I'll add my backend code here. @HMR
    • HMR
      HMR over 6 years
      the easiest way would be to install the Allow-Control-Allow-Origin: * extension for chrome: chrome.google.com/webstore/detail/allow-control-allow-origi/‌​…
    • rk_Tinelli
      rk_Tinelli over 6 years
      I'm trying to avoid that since this project will need to run in another computer that I'm not responsible for. I'll give instructions to the end user, but maybe there is a way to do this programmatically.
    • HMR
      HMR over 6 years
      If you're running your front end code with webpack dev server then just connect to same host as your web page (your api calls should not have the host and port in the url anyway but just the absolute path /API/SOMEAPI) dev server allows you to proxy these requests to somewhere: webpack.js.org/configuration/dev-server/#devserver-proxy
  • rk_Tinelli
    rk_Tinelli over 6 years
    I couldn't get then to run in the same port in this scenario, if my backend is already running in port 3000, for example, when i give to command npm start to my client i get the following message: ? Something is already running on port 3000. Would you like to run the app on another port instead? (Y/n) But, in the opposite scenario, I mean, if my client is already running at port 3000 and send to command node index do my backend, it works fine. I'll edit my question with my backend code, because each system running in different ports. Thanks for the reply by the way.
  • rk_Tinelli
    rk_Tinelli over 6 years
    Here, I edited my question with my index.js code for my backend.
  • rk_Tinelli
    rk_Tinelli over 6 years
    hey @JoshSiegl I think it is working now, I followed the instructions in this link link. Now I'm getting a 401 error, which is related to unauthorized access. I'm already searching for it
  • Josh Siegl
    Josh Siegl over 6 years
    Awesome @rk_Tinelli, that's good news. I'm glad I could help.
  • Michael Qin
    Michael Qin over 4 years
    Hi @rk_Tinelli, how did you solve the 401 issue with basic auth? Would you like to share? Thanks, I guess setting credentials: "include" in the request headers might be the solution?
  • rk_Tinelli
    rk_Tinelli over 4 years
    Hey @MichaelQin unfortunately i had to drop this project after a few weeks due to some changes in my work, so i don't have a proper solution for that, but thanks for bringing a new suggestion.