Search code examples
javascriptflaskxmlhttprequest

cURL works but XMLHttpRequest does not?


Making this call from terminal works:

curl -d "username=test&password=test" -X POST http://127.0.0.1:5000/login/

But from my Chrome Extension, an Ajax call fails with status 0. I've tried a number of things but haven't had any luck.

function doLogin() {
    var username = document.getElementById("username").value;
    var password = document.getElementById("password").value;
    var params = 'username=' + username + '&password=' + password;

    sendPostRequest("http://127.0.0.1:5000/login/", params);
}

function sendPostRequest(url, params) {
    var http = new XMLHttpRequest();
    http.open('POST', url, true);
    http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

    http.onreadystatechange = function () {
        // This is never called
        if (this.readyState == 4 && this.status == 200) {
            alert(http.status);
        }
    };

    http.send(params);
}

Server-side:

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

    auth = authenticate(username, password)

    return jsonify({'authentication': auth}), 200

I would appreciate feedback.


Solution

  • I have recreated the scenario. If you want to access the login route from outside of the templates folder, you need to allow CORS.

    I have installed flask-cors and allowed all origins. You may change this to specific login route if necessary. Documentation of the package can be found in this documentation link.

    Folder structure:

    ├── app.py
    ├── extension.html
    └── requirements.txt
    

    requirements.txt:

    Click==7.0
    Flask==1.0.2
    Flask-Cors==3.0.7
    itsdangerous==1.1.0
    Jinja2==2.10.1
    MarkupSafe==1.1.1
    pkg-resources==0.0.0
    six==1.12.0
    Werkzeug==0.15.2
    

    app.py:

    from flask import Flask, request, jsonify
    from flask_cors import CORS
    
    app = Flask(__name__)
    CORS(app)
    
    def authenticate(username, password):
        if username == "test" and password == "test":
            return True
        return False
    
    @app.route("/login/", methods=['POST'])
    def login():
        username = request.form["username"]
        password = request.form["password"]
        auth = authenticate(username, password)
        return jsonify({'authentication': auth}), 200
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=5000)
    

    extension.html:

    <html>
    <head>
      <title>Chrome Extension Login</title>
    </head>
    <body>
      <div>
        Username: <input type="text" id="username" /> <br>
        Password: <input type="text" id="password" /> <br>
        <button id="login_button">Login</button>
      </div>
      <script type="text/javascript">
      function doLogin() {
        var username = document.getElementById("username").value;
        var password = document.getElementById("password").value;
        var params = 'username=' + username + '&password=' + password;
        sendPostRequest("http://127.0.0.1:5000/login/", params);
      }
      function sendPostRequest(url, params) {
        var http = new XMLHttpRequest();
        http.open('POST', url, true);
        http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        http.onreadystatechange = function () {
          if (this.readyState == 4 && this.status == 200) {
            console.log(this.status);
            console.log(this.responseText);
          }
        };
        http.send(params);
      }
      var login_button = document.getElementById("login_button");
      login_button.addEventListener("click", doLogin);
      </script>
    </body>
    </html>
    

    Output:

    CURL request:

    curl request example

    Successful login with correct credentials:

    successful login

    Error in login with wrong credentials:

    error in login