12

My login endpoint looks like

@app.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        print request.form # debug line, see data printed below
        user = User.get(request.form['uuid'])
        if user and hash_password(request.form['password']) == user._password:
            login_user(user, remember=True)  # change remember as preference
            return redirect('/home/')
    else:
        return 'GET on login not supported'

When I test this using curl, the GET call looks like

⮀ ~PYTHONPATH ⮀ ⭠ 43± ⮀ curl http://127.0.0.1:5000/login/
GET on login not supported

but on POST, I am not able to access the form data and get HTTP 400

⮀ ~PYTHONPATH ⮀ ⭠ 43± ⮀ curl -d "{'uuid': 'admin', 'password': 'admin'}" http://127.0.0.1:5000/login/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>The browser (or proxy) sent a request that this server could not understand.</p>

On the server though, my debug information prints the following

ImmutableMultiDict([("{'uuid': 'admin', 'password': 'admin'}", u'')])

where I do print request.form. I am not able to understand where I am doing wrong

davidism
  • 121,510
  • 29
  • 395
  • 339
daydreamer
  • 87,243
  • 191
  • 450
  • 722

2 Answers2

8

You are not using curl correctly. Try like this:

curl -d 'uuid=admin&password=admin'

The 400 Bad Request error is the usual behavior when you try to get nonexistent keys from request.form.

Alternatively, use request.json instead of request.form and call curl like this:

curl -d '{"uuid":"admin","password":"admin"}' -H "Content-Type: application/json" 
janos
  • 120,954
  • 29
  • 226
  • 236
6

You still need to return a response:

from flask import abort

@app.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        user = User.get(request.form['uuid'])

        if user and hash_password(request.form['password']) == user._password:
            login_user(user, remember=True)
            return redirect('/home/')
        else:
            return abort(401)  # 401 Unauthorized
    else:
        return abort(405)  # 405 Method Not Allowed

Here's the documentation for custom Flask error pages.

Also, take a look at Flask-Bcrypt for password hashing.


Your CURL command line isn't valid. JSON objects need to have double quotes around the keys and values:

$ curl -d '{"uuid": "admin", "password": "admin"}' http://127.0.0.1:5000/login/

Now, you can access the keys with request.json.

Blender
  • 289,723
  • 53
  • 439
  • 496
  • Thanks @Blender, but the question is why I am not able to access `uuid` when I am sending the data form client? – daydreamer Apr 06 '13 at 21:10
  • 1
    @daydreamer: Flask sends that response only if you access a key that doesn't exist in the [`request.form` object](http://flask.pocoo.org/docs/quickstart/#the-request-object). Try using `request.form.get('uuid', None)`. – Blender Apr 06 '13 at 21:17
  • As mentioned in my question, my `request.form` is `ImmutableMultiDict([("{'uuid': 'admin', 'password': 'admin'}", u'')])` – daydreamer Apr 06 '13 at 21:18
  • @daydreamer: I know. How are you sending this request? – Blender Apr 06 '13 at 21:19
  • like this `curl -X POST -d '{uuid: "admin", "password": "admin"}' http://127.0.0.1:5000/login/` – daydreamer Apr 06 '13 at 21:20
  • @daydreamer: You're sending a JSON object with the POST request, not a regular form POST request. Use `response.json` to access it. – Blender Apr 06 '13 at 21:21
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/27705/discussion-between-daydreamer-and-blender) – daydreamer Apr 06 '13 at 21:21