Django Rest Framework not accepting JWT Authentication Token - django

I am using the Django Restful API Framework together with Simple JWT and have successfully created a URL for receiving and refreshing a user token.
In order to try out the authentication using the token, I have created a view that simply lists all the posts inside the database. I have then assigned the IsAuthenticated class to the view.
As expected, I get an error message saying that the authentication credentials were not provided. I then went ahead and made a simple GET request using Postman, with the authentication token provided in the "Authorization" tab. The type was set to "Bear Token". Unfortunately, I still get the message "Authentication credentials were not provided." with a 403 Forbidden code.
I have also tried to provide the token in the Headers, as well as make CURL requests, everything to no avail.
My view looks like this:
class PostListView(generics.ListAPIView):
permission_classes = (IsAuthenticated,)
queryset = Post.objects.filter()
This is the serializer:
class PostListSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('__all__')
The settings.py of the Django project:
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'],
'DEFAULT_AUTHENTICATION_CLASSES:': ('rest_framework_simplejwt.authentication.JWTAuthentication',)
}
CORS_ALLOW_ALL_ORIGINS = True # For testing purposes
I have followed several different tutorials online, read through numerous posts as well as followed the official documentation of Simple JWT.

Well what you are doing is trying to filter the data while your basic purpose is to just list your model. For filtering make sure your go through the documentation DRF Filtering.
Try these changes in your code. I hope it will work for you.
Settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
Views.py
class UserList(generics.ListAPIView):
permission_classes = (IsAuthenticated,)
queryset = Post.objects.all()
serializer_class = PostListSerializer
After this try to hit your API with access token. To learn more about generic views you can go through this link Generic Views in DRF.

Related

CSRF cookie not set when calling POST request API view

I have encountered a weird behavior as it works with one view but does not with another.
Django 3.2 and rest framework 3.13.1 are currently installed within the venv.
When I call the view I get the error message: CSRF validation failed, reason CSRF cookie not set.
This view uses its authentication class that extends TokenAuthentication.
class APIKeyAuthentication(authentication.TokenAuthentication):
logger = logging.getLogger(__name__)
def authenticate(self, request):
# try to get api key via X-API_KEY
api_key = request.META.get("HTTP_X_API_KEY")
# try to get api key via Authorization
if not api_key:
api_key = request.META.get("HTTP_AUTHORIZATION")
if not api_key:
return None
platform_id, api_user = self.validate_api_token(api_key)
return api_user, None
That class is used as default within rest framework:
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"api.authentification.APIKeyAuthentication",
"rest_framework.authentication.BasicAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated",
],
Endpoints are:
path("v1/combinedEntries", VerifyV1OrderView.as_view()),
path("order/verify/", VerifyOrderView.as_view()),
Classes:
class VerifyV1OrderView(GenericAPIView):
serializer_class = CombinedEntryV1Serializer
authentication_classes = (APIKeyAuthentication,)
and
class VerifyOrderView(GenericAPIView):
serializer_class = CombinedEntrySerializer
authentication_classes = (APIKeyAuthentication,)
so I do not understand the error I even removed the session authentication from the config but without any change.
I am using Postman to send the requests but the error occurs also when using curl.
Has someone an idea what the problem could be?
Thanks and regards.
Matt

How to test Django REST Framework Login Protected API using postman?

I need to test REST API using postman. API is build using Django REST Framework. Only login user can get access to API. I am not able to find how I can send login credentials using postman. Thanks in advance.
class ApiMemberGroupNameList(views.APIView):
permission_classes = (
permissions.IsAuthenticated,
RequiredOrgPermission,
RequiredOrgStaffMemberPermission)
def get(self, request, **kwargs):
pk = kwargs.get('pk')
hash = kwargs.get('hash')
member_obj = get_object_or_404(Member.objects.filter(org__hash=hash, pk=pk))
return Response(GroupListSerializer(member_obj.groups.all(), many=True).data)
You can use Basic Auth in POSTMAN. Refer to this screenshot:
You could change the HTTP Methods, URLs, Data Payload(under Body tab) etc in the POSTMAN console
UPDATE-1
After your comments, I tried to recreated the problem.What I did was:
created a view
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
class MySampleView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request):
return Response(data={"status": True})
Added to urls.py
urlpatterns = [
url(r'^mysampleview/$', MySampleView.as_view())
]
And my POSTMAN response are below:
Authorization Screenshot
Header Screenshot
My conclusion
You may enter wrong credentials, or something else. I would suggest you open a new POSTMAN tab and repeat the procedure, also try to login Django admin using the same credential which is already used in POSTMAN.
If you want to use Basic Authentification to test Django REST API, it must be allowed in Django REST Framework settings:
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
...

django-rest-framwork UpdateView, DeleteView occurs csrf token error?

I'm using django-rest-framework and implement very simple post CRUD API.
But the problem is UpdateView and DeleteView occurs csrf error
"detail": "CSRF Failed: CSRF token missing or incorrect."
Strange thing is CreateView doens't require csrf and works very well.
Here is my view and serializer
views.py
class PostEditAPIView(RetrieveUpdateAPIView):
"""
http://example.com/posts/1/edit
"""
queryset = Post.objects.all()
serializer_class = PostUpdateSerializer
lookup_url_kwarg = 'post_id'
serializer.py
class PostUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = [
"title",
"content",
]
I think this is enough for source code.
After clicked PUT button,
How can I deal with csrf in API?
I didn't touch any SETTINGS about Rest-framework
One of the solutions I like to use is to forcefully remove any and all kinds of CSRF checks by instructing Django to do so in the middlewares level.
To do this, create a new middleware class which contains the code to disable CSRF checks, and add the middle ware to your existing list of middlewares to run. Make sure you add your custom middleware AFTER the default authentication middleware being used by Django (Order of middlewares in settings matters).
class CSRFDisablerMiddleware(object):
def process_request(self, request):
setattr(request, '_dont_enforce_csrf_checks', True)
Beware I safely use this method since my app is protected using other means of authentication. I am not sure about how you would go about solving this problem if your project needs CSRF authentication in certain areas and not in others. The method described above will disable CSRF authentication throughout your entire Django project.

Multiple Token Authentication in Django Rest Framework

How can a user login in multiple devices because what we have is just a single Token Authentication on our django app. As an authenticated user when I login on Google Chrome it works fine but when I visit at the mozilla time and I logged out at the chrome the token that has been created has been deleted upon logout so when I login at mozilla, the token is already gone and we can not log-in on mozilla and throws a Forbidden response on the console.
You're question is a little convoluted, but I think you are getting at the problem referenced here:
https://github.com/tomchristie/django-rest-framework/issues/601
The official token authentication does not support (and unfortunately has no intention of supporting) multiple tokens, but you may be able to use django-rest-knox, available here: https://github.com/James1345/django-rest-knox
Edit: I previously recommended django-rest-multitoken, but django-rest-knox seems to be more actively maintained.
It's been years since this question was asked, I worked around this issue with few lines of code, I hope someone will benefit from this.
DRF authentication relies on two things:
Token model (which is the source of this issue).
Authentication class.
I provided my own implementations of these two, and passed them to DRF.
# models.py
from django.conf import settings
from django.db import models
from rest_framework.authtoken.models import Token
class MultiToken(Token):
user = models.ForeignKey( # changed from OneToOne to ForeignKey
settings.AUTH_USER_MODEL, related_name='tokens',
on_delete=models.CASCADE, verbose_name=_("User")
)
Then I implemented an Authentication class, just to override the model.
# appname.authentication.py
from rest_framework.authentication import TokenAuthentication
from appname.models import MultiToken
class MultiTokenAuthentication(TokenAuthentication):
model = MultiToken
Pass this Authentication class, to DRF.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'appname.authentication.MultiTokenAuthentication',
],
...
}
of course, Since I inherited from DRF Token model, I had to remove rest_framework.authtoken from INSTALLED_APPS.
I also, changed the ObtainAuthToken APIView to suit this new change.
class LoginApi(ObtainAuthToken):
def post(self, request, *args, **kwargs):
context = dict(request=request, view=self)
serializer = self.serializer_class(data=request.data, context=context)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
update_last_login(None, user, )
token = MultiToken.objects.create(user=user)
data = {'token': token.key}
return Response(data)
HOPE THIS HELPS.

How to get a valid csrf token when using tastypie?

I am using tastypie to create an api for my Django project. My project requires that the user logins in order to make edits to models view etc. So my first step was to login the user using tastypie by creating the login and logout functions in the UserResource as described here. The response contained a sessionid cookie that i used to logout. My resources use SessionAuthentication and DjangoAuthorization. But when i try to post or put or delete on a model using a tastypie resource url, I get an error a 401 error. Some people suggested that i must use a valid csrf_token. But how can i do that when tastypie login view won't return one.
example code:
class EntryResource(ModelResource):
customer = fields.ForeignKey(CustomerResourse, 'customer', full=True)
creator = fields.ForeignKey(UserResource,'creator',null=True,full=True,blank=True)
class Meta:
queryset = Entry.objects.all()
resource_name = 'entry'
authorization = DjangoAuthorization()
authentication = SessionAuthentication()
my client.py
headers={"Content-Type":"application/json"}
#login. I don't get a csrftoken here, but works fine which is odd because i post data r
resp = requests.post(login_url, data=json.dumps(credentials), headers=headers)
cookies ={'sessionid':resp.cookies['sessionid']}
entry = {
'title':'New Entry',
'snippet':'New Snippet',
'created': datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
}
entry_json = json.dumps(entry)
entry_add_response = requests.post(entry_api_url,data=entry_json,
headers=headers,cookies=cookies)
#entry_add_response.status_code is 401
#logout works as it should
logout_resp = requests.get(logout_url, cookies=cookies)
what am i doing wrong? Am I not doing the right steps?
all my urls have ?format=json appended to them. Tried without didn't work. I also tried changing from django and session authentication and authorization to basic (Authentication(), Authorization() ). I then get a 500 error. I starting to feel a bit desperate....