1

I am writing a Flask RESTful server and an AngularJS client, and am running into an issue where it appears the username and password information are being lost in transmission, so to speak.

In the Javascript console, I can tell that the client is sending the the Authorization header as expected: Authorization: Basic username:password. However, within the @auth.verify_password callback, they are both both empty.

I have a fair bit of unit tests around the server portion of the code, and the auth information appears to be present in all of them, so it is reassuring that I can at least get the username and password from within the header in some instances.

Additionally, I have added the CORS extension to the server code, and allow it server wide. It appears that an OPTIONS(which always returns 200) to the below url is always called immediately before the GET(returns 401, due to username and password issue) to the same url.

Reference code:

Server auth callback:

@app.route('/api/users/token')
@auth.login_required
def get_auth_token():
    token = g.user.generate_auth_token()
    return jsonify({ 'token': token.decode('ascii') })

@auth.verify_password
def verify_password(email_or_token, password):
    print 'email_or_token: ' + email_or_token
    print 'password: ' + password
    ...

Server Unit test code behaving as expected:

def _get_user_token(self, email=TEST_EMAIL, password=TEST_PASSWORD):
    headers = {
        'Authorization': 'Basic ' + b64encode("{0}:{1}".format(email, password))
    }
    response = self.app.get('/api/users/token', headers=headers)
    return response

AngularJS code which yields appropriate header when inspected in browser but empty username and password in auth callback:

$http.get(silkyAppConstants.BASE_URL + '/api/users/token', {
  headers: { "Authorization": "Basic " + username + ":" + password }
})
Brent Hronik
  • 2,357
  • 1
  • 27
  • 43
  • Have you tried adding the `withCredentials: true` in your `$http.get` call? – tommyd456 Aug 25 '15 at 15:40
  • @tommyd456 just gave that a shot, I know see just the OPTIONS call, server responds to that with a 200, but there is no GET request afterwards. – Brent Hronik Aug 26 '15 at 03:16
  • @tommyd456 that was due to the server not adding the 'Access-Control-Allow-Credentials' true to the header. Added that but still no at square 1 now. – Brent Hronik Aug 26 '15 at 04:03
  • As there is an answer now, let me know if it works as I had a tough time getting something similar going myself. – tommyd456 Aug 26 '15 at 08:24
  • Could you also see if it works with the suggested answer below but without the `withCredentials` suggestion – tommyd456 Aug 26 '15 at 08:31
  • @tommyd456 yes, I can confirm that he issue was just that the contents had to be base64 encoded. – Brent Hronik Sep 10 '15 at 00:58

1 Answers1

2

I suspect your problem is that you are sending an invalid Authorization header. The username + ":" + password portion of the header must be base64 encoded (see Section 2 of RFC 2617. When Flask receives the plain text credentials that you are sending it is trying pass it through a base64 decoder and that fails.

Community
  • 1
  • 1
Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • Thanks @Miguel, just realized that is the likely suspect as well. I began comparing the raw request header between the unittests and the client code, and noticed the differing on the encoding. – Brent Hronik Aug 26 '15 at 04:22