Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test an API endpoint with Django-rest-framework using Django-oauth-toolkit for authentication

Tags:

I have a Django-rest-framework viewset/router to define an API endpoint. The viewset is defined as such:

class DocumentViewSet(viewsets.ModelViewSet):     permission_classes = [permissions.IsAuthenticated, TokenHasReadWriteScope]     model = Document 

And the router is defined as

router = DefaultRouter() router.register(r'documents', viewsets.DocumentViewSet) 

with url pattern url(r'^api/', include(router.urls))

I can hit this endpoint in the browser/through curl just fine by getting the right access token and using it for authorization. However, it's not clear how to write tests against this endpoint.

Here is what I've tried:

class DocumentAPITests(APITestCase):     def test_get_all_documents(self):         user = User.objects.create_user('test', '[email protected]', 'test')         client = APIClient()         client.credentials(username="test", password="test")         response = client.get("/api/documents/")         self.assertEqual(response.status_code, 200)  

This fails with an HTTP 401 response from the client.get() call. What is the right way to test an API endpoint in DRF using django-oauth-toolkit for oauth2 authentication?

like image 811
Jim Avatar asked Dec 24 '14 20:12

Jim


People also ask

How do you implement OTP based authentication in Django REST framework?

Step 1: Find that phone number existing in the phone model. Step 2: Generate a key of base32 using base64 library. Step 3: Use the Key to generate an Object of class pyotp. Step 4: Now using the Counter of User model and OTP code sent by the user, validate the authenticity of the user.

Which authentication is best in Django REST framework?

And these are all provided by drf(django rest framework) and other than these like oauth, oauth2 based authentication are provided by the efforts of the community with help of other python packages. And they can be easily used in the production environment.


2 Answers

When you are writing tests, you should aim to extract anything you are not testing from the test itself, typically putting any setup code in the setUp method of the test. In the case of API tests with OAuth, this usually includes the test user, OAuth application, and the active access token.

For django-oauth-toolkit, and other Django applications, I would always recommend looking at the tests to see how they do it. This allows you to avoid making unneeded API calls, especially for multi-part processes like OAuth, and only create the few model objects that are required.

def setUp(self):     self.test_user = UserModel.objects.create_user("test_user", "[email protected]", "123456")      self.application = Application(         name="Test Application",         redirect_uris="http://localhost",         user=self.test_user,         client_type=Application.CLIENT_CONFIDENTIAL,         authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,     )     self.application.save()  def test_revoke_access_token(self):     from datetime import datetime     from django.utils import timezone      tok = AccessToken.objects.create(         user=self.test_user, token='1234567890',         application=self.application, scope='read write',         expires=timezone.now() + datetime.timedelta(days=1)     ) 

From there you just need to authenticate using the token that has been generated. You can do this by injecting the Authorization header, or you can use the force_authenticate method provided by Django REST Framework.

like image 156
Kevin Brown-Silva Avatar answered Oct 02 '22 01:10

Kevin Brown-Silva


I have used the same library for OAuth2,

This worked for me

from oauth2_provider.settings import oauth2_settings from oauth2_provider.models import get_access_token_model,  get_application_model from django.contrib.auth import get_user_model from django.utils import timezone from rest_framework.test import APITestCase  Application = get_application_model() AccessToken = get_access_token_model() UserModel = get_user_model()  class Test_mytest(APITestCase):      def setUp(self):          oauth2_settings._SCOPES = ["read", "write", "scope1", "scope2", "resource1"]          self.test_user = UserModel.objects.create_user("test_user", "[email protected]", "123456")          self.application = Application.objects.create(                                                 name="Test Application",                                                 redirect_uris="http://localhost http://example.com http://example.org",                                                 user=self.test_user,                                                 client_type=Application.CLIENT_CONFIDENTIAL,                                                 authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,                                             )          self.access_token = AccessToken.objects.create(                                                     user=self.test_user,                                                     scope="read write",                                                     expires=timezone.now() + timezone.timedelta(seconds=300),                                                     token="secret-access-token-key",                                                     application=self.application                                                 )         # read or write as per your choice         self.access_token.scope = "read"         self.access_token.save()          # correct token and correct scope         self.auth =  "Bearer {0}".format(self.access_token.token)      def test_success_response(self):          url = reverse('my_url',)          # Obtaining the POST response for the input data         response = self.client.get(url, HTTP_AUTHORIZATION=self.auth)          # checking wether the response is success         self.assertEqual(response.status_code, status.HTTP_200_OK) 

Now everything will work as expected. Hope this helps. Thanks

like image 43
Shinto Joseph Avatar answered Oct 02 '22 01:10

Shinto Joseph