Call Django's authenticate function with the request object by jgeerds · Pull Request #5295 · encode/django-rest-framework (original) (raw)

Django 1.8.x, 1.9.x and 1.10.x releases use the following function signature:

def authenticate(**credentials):

This implies that it is not possible to use positional keyword arguments with this function:

In [7]: def authenticate(**credentials):
   ...:     print(credentials)
   ...: 

In [8]: authenticate('foo', 'bar')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-b0a7d48cf507> in <module>()
----> 1 authenticate('foo', 'bar')

TypeError: authenticate() takes 0 positional arguments but 2 were given

In [9]: authenticate(username='foo', password='bar')
{'password': 'bar', 'username': 'foo'}

In [10]: 

I think this is also the reason why Django 1.11 introduced request as a keyword argument as well (at least until 2.1 comes out). Passing an extra request parameter works fine with pre-1.11:

In [12]: def authenticate(**credentials):
    ...:     print(credentials)
    ...: 

In [13]: authenticate(request='req', username='foo', password='bar')
{'request': 'req', 'password': 'bar', 'username': 'foo'}

However, from a custom auth backend perspective I think it might fail because of this:

    for backend, backend_path in _get_backends(return_tuples=True):
        try:
            inspect.getcallargs(backend.authenticate, **credentials)
        except TypeError:
            # This backend doesn't accept these credentials as arguments. Try the next one.
continue

I'll create a wrapper function in compat.py to handle old versions