12

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?

4 Answers 4

28

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I was using Django Rest API with token authentication and required to change it to: response = self.client.get('/api/someurl', {}, HTTP_AUTHORIZATION='Token {}'.format(self.token))
4

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.

Comments

1

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

Comments

0

Create a basic method:

def create_jwt_token(user) -> str:
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    payload = jwt_payload_handler(user)
    token = jwt_encode_handler(payload)
    return 'JWT ' + token

In your test, use it like this:

@classmethod
    def setUpTestData(cls):
        cls.valid_auth_headers = {
            "HTTP_AUTHORIZATION": UserTestUtils.create_jwt_token(cls.user)
        }

def test_valid_accepted_inputs_only(self):
        response = self.client.post(
            self.url,
            {
                "name": 'NewFarmName',
                "age": 2010
            },
            **self.valid_auth_headers,
        )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.