Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test authentication using REST Framework JWT?

JWT based authentication works well using POST requests sent from mobile and "advanced rest client", however it fails when using the Django test client. The client successfully receives the token when requested, but it gets the following response when trying to access a restricted view using that token.

"Authentication credentials were not provided."

The test case:

def test_get_token(self):
        response = self.client.post("/auth/api/get_token/", {"username": "Heffalumps", "password": "Woozles"})
        self.assertEqual(response.status_code, 200, "The token should be successfully returned.")

        response_content = json.loads(response.content.decode('utf-8'))
        token = response_content["token"]

        # The following request fails
        response = self.client.post("/auth/api/authenticated/", {}, Authorization='JWT ' + token)
        response_content = json.loads(response.content.decode('utf-8'))

        self.assertEqual(response_content["authenticated"], "mooh", "The user should be able to access this endpoint.")

Outgoing request from test client: enter image description here

The restricted view:

class RestrictedView(APIView):
    permission_classes = (permissions.IsAuthenticated, )
    authentication_classes = (JSONWebTokenAuthentication, )

    def post(self, request):

        response_data = json.dumps({"authenticated": "mooh"})

        return HttpResponse(response_data, content_type='application/json')

Am I missing something from the test case?

like image 540
Marlyyy Avatar asked Oct 11 '15 14:10

Marlyyy


People also ask

How does JWT authentication work in REST API?

Once verified, the API will create a JSON Web Token and sign it using a secret key. Then, the API will return that token back to the client application. Finally, the client app will receive the token, verify it on its own side to ensure it's authentic, and then use it on every subsequent request.

How do I authenticate with JWT?

To authenticate a user, a client application must send a JSON Web Token (JWT) in the authorization header of the HTTP request to your backend API. API Gateway validates the token on behalf of your API, so you don't have to add any code in your API to process the authentication.

How JWT works in Django REST framework?

Implementing JWT in Django REST Framework In this mechanism, the server generates a token for the authenticated user and the user has to send the token along with all the HTTP requests to identify themselves. In order to use JWT, we need to configure Django-rest-framework permissions to accept JSON Web Tokens.


3 Answers

Okay, the following seems to have solved the issue:

Instead of:

response = self.client.post("/auth/api/authenticated/", {}, Authorization='JWT ' + token)

I had to write:

response = self.client.post("/auth/api/authenticated/", {}, HTTP_AUTHORIZATION='JWT {}'.format(token))

Authentication works now through the Django test client as well.

like image 118
Marlyyy Avatar answered Oct 31 '22 17:10

Marlyyy


Also keep in mind that when you create the user, you have to use the hashed version for the password. E.g.:

User(email='[email protected]', password=make_password('TestPassword')))

(Using djangos password hashers)

While when calling /auth/api/get_token/ you have to use the clear case password. E.g.:

response = self.client.post("/auth/api/get_token/", {'email': '[email protected]', 'password': 'TestPassword'})

Took me a while to find out that the request responded 'non_field_errors': ['Unable to log in with provided credentials.'] because I didn't use the hasher while creating the user.

like image 35
seblat Avatar answered Oct 31 '22 16:10

seblat


It may be helpful to note that, when using JWT via OAuth2, the following code creates the authentication credentials:

self.client.post("/auth/api/authenticated/", {}, HTTP_AUTHORIZATION='Bearer {0}'.format(token))

Django Rest Framework, however, includes scaffolding to authenticate a request: http://www.django-rest-framework.org/api-guide/testing/#forcing-authentication

Additionally, there are some interesting tests here: https://github.com/jpadilla/django-jwt-auth/blob/master/tests/test_mixins.py

like image 30
Brian Avatar answered Oct 31 '22 17:10

Brian