0

I habe a client written in Javascript (react) which runs on localhost:3000 Here I have a button that sends the credentials to my backend written in python and using flask. The endpoint is running on localhost:5000/login.

My frontend code looks like this:

loginToDatabase = async () => {
    console.log("login to database. user: " + this.state.user+" pw: "+this.state.password);     

    const response = await fetch("http://localhost:5000/login",{
        method: 'POST',
        body: {
            "user": this.state.user,
            "password": this.state.password
        }, 
        headers: {
            "Content-Type": "application/json"
        }
    });
    console.log("response: "+response)
};

My backend code looks like this:

@app.route("/login", methods=['POST'])
def login():

    jsonRequest = request.get_json()
    receivedUser = jsonRequest.get('user')
    receivedPassword = jsonRequest.get('password')

isConnected = opendatabase.openDatabase('localhost',receivedUser,receivedPassword)

if(isConnected == True):
    body = json.dumps({
        "connection":isConnected,
    })

    jsonResponse = Response(
        body,
        mimetype="application/json",
        headers={
            "Access-Control-Allow-Origin" : "*",
        }
    )
    return (jsonResponse)
else:
    body = isConnected

    jsonResponse = Response(
        body,
        headers={
            "Access-Control-Allow-Origin" : "*",
    )
    return (jsonResponse, 401)

Testing the API with Postman works as expected. However using the frontend I receive this error:

Access to fetch at 'http://localhost:5000/login' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

After doing some research I figured out why this happens and that I need the header

"Access-Control-Allow-Origin" : "*"

which I included. But still could not make it work. I then read here https://developer.mozilla.org/de/docs/Web/HTTP/CORS that does not work with application/json.

The only allowed values for the Content-Type header are: application/x-www-form-urlencoded, multipart/form-data, text/plain

However I also read here Can't send a post request when the 'Content-Type' is set to 'application/json' that I can set a header

->header('Access-Control-Allow-Headers', 'Content-Type');

which I also tried like this:

if(isConnected == True):
    body = json.dumps({
        "connection":isConnected,
    })

    jsonResponse = Response(
        body,
        mimetype="application/json",
        headers={
            "Access-Control-Allow-Origin" : "*",
            "Access-Control-Allow-Headers": "Content-Type",

        }
    )
    return (jsonResponse)
else:
    body = isConnected

    jsonResponse = Response(
        body,
        headers={
            "Access-Control-Allow-Origin" : "*",
            "Access-Control-Allow-Headers": "Content-Type"
            }
    )
    return (jsonResponse, 401)

But that does also not work. There are also many more posts about this topic but so far I could not find a solution. I am also new to APIs and webdevelopment. And also I think my shown login process is far from perfect. It is really just about getting the REST call to work.

Is there a way to solve this and still using JSON? Surely I could use someting like text/plain but that would not be satisfying.

Also (maybe related) if I use text/plain in the frontend I don't receive the error, but in the backend I don't know how the receive the data send via POST. As you can see in the attached picture, I seem to get an empty object?

enter image description here

Where is my mistake and what is the best way to solve this issue with JSON?

Mrob
  • 281
  • 4
  • 16
  • with `"Content-Type": "application/json"` the browser will make a pre-flight `OPTIONS` request - do you handle that request? – Bravo Oct 13 '19 at 10:22
  • 2
    You can try allow cors from server side for flask by using [flask cors](https://flask-cors.readthedocs.io/en/latest/) – ChickenSoups Oct 13 '19 at 10:37
  • +1 for using flask-cors. CORS issues can only be solved on the server side, and that package makes it easy without having to worry about the details. – Robin Zigmond Oct 13 '19 at 10:49
  • @Bravo I have seen that it makes the OPTIONS preflight. But I thought he checks 'preflight' if the REST call is ok and that is where he responds with the CORS error. Do I have to handle it in a different way? – Mrob Oct 13 '19 at 11:25
  • @ChickenSoups wokrs perfectly thank you. Can you point out what flask-cors is doing 'behind the curtain'? The documentation is not that clear about it. – Mrob Oct 15 '19 at 16:43
  • You can refer to the source code of flash cors on github. It just construct [a cors options](https://github.com/corydolphin/flask-cors/blob/master/flask_cors/core.py#L113) depend on the [default options](https://github.com/corydolphin/flask-cors/blob/master/flask_cors/core.py#L52) and your customize options, then [add all options to attributes](https://github.com/corydolphin/flask-cors/blob/master/flask_cors/core.py#L224) of your **response header**. Perhap you can do it your self in each of your request. – ChickenSoups Oct 16 '19 at 03:29

0 Answers0