Flask werkzeug request.authorization is none but Authorization headers present

Patrick Yan picture Patrick Yan · Dec 24, 2014 · Viewed 11.1k times · Source

I am POSTing some JSON data and adding an Authorization header. However, the request object does not have the correct authorization property. HTTP_AUTHORIZATION and headers both show the proper authorization details.

{'authorization': None,
 'cookies': {},
 'environ': {'CONTENT_LENGTH': '81',
             'CONTENT_TYPE': u'application/json',
             'HTTP_AUTHORIZATION': 'testkey:',
             'HTTP_CONTENT_LENGTH': '81',
             'HTTP_CONTENT_TYPE': 'application/json',
             'HTTP_HOST': 'test',
             'PATH_INFO': '/v1/test',
             'QUERY_STRING': '',
             'REQUEST_METHOD': 'POST',
             'SCRIPT_NAME': '',
             'SERVER_NAME': 'test',
             'SERVER_PORT': '80',
             'SERVER_PROTOCOL': 'HTTP/1.1',
             'flask._preserve_context': False,
             'werkzeug.request': <Request 'http://test/v1/test' [POST]>,
             'wsgi.errors': <open file '<stderr>', mode 'w' at 0x10d5471e0>,
             'wsgi.input': <_io.BytesIO object at 0x11074c410>,
             'wsgi.multiprocess': False,
             'wsgi.multithread': False,
             'wsgi.run_once': False,
             'wsgi.url_scheme': 'http',
             'wsgi.version': (1, 0)},
 'headers': EnvironHeaders([('Authorization', testkey:'), ('Host', u'test'), ('Content-Length', u'81'), ('Content-Type', u'application/json')]),
 'shallow': False,
 'url': u'http://test/v1/test',
 'url_rule': <Rule '/v1/test' (POST, OPTIONS) -> testresource>,
 'view_args': {}}

Answer

Martijn Pieters picture Martijn Pieters · Dec 25, 2014

The request.authorization attribute is only set when you have a valid Basic Authorization or Digest Authorization header; the Authorization header has specific formats where the first word in the header value sets the type, and the attribute only handles those two specific types (flagged by the Basic or Digest type keywords).

From the AuthorizationMixin.authorization attribute documentation

The Authorization object in parsed form.

following that to the Authorization object docs:

Represents an Authorization header sent by the client. You should not create this kind of object yourself but use it when it’s returned by the parse_authorization_header function.

which is documented as:

Parse an HTTP basic/digest authorization header transmitted by the web browser. The return value is either None if the header was invalid or not given, otherwise an Authorization object.

Bold emphasis mine.

Your header is not such a valid header; it is doesn't have the Basic or Digest type indicator. If you did have such a header the function returns something other than None:

>>> from werkzeug.http import parse_authorization_header
>>> parse_authorization_header('testkey:')
>>> parse_authorization_header('testkey:') is None
True
>>> parse_authorization_header('Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==')
{'username': 'Aladdin', 'password': 'open sesame'}
>>> result = _
>>> type(result)
<class 'werkzeug.datastructures.Authorization'>
>>> result.username
'Aladdin'
>>> result.password
'open sesame'

I used a Basic type header there, where the remainder of the header value is a base-64 encoded username and password pair separated by a : colon.

If you want to implement your own authentication scheme, just access the header itself and parse it manually.

auth = request.headers.get('authorization')