django restframework token Authentication fail with "invalid token" - django

I have a problem with token authentication.
I run my django app with django built in server.
$python manage.py runserver
My App's urls.py
from rest_framework_jwt.views import obtain_jwt_token
from .views import LectureCreateView
urlpatterns = [
...
url(r'^api/user_auth/$', obtain_jwt_token),
url(r'^api/lecture/create/$', LectureCreateView.as_view()),
]
My App's models.py
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class LectureStartView(APIView):
permission_classes = (IsAuthenticated,)
authentication_classes = (TokenAuthentication,)
def post(self, request):
...
and settings.py
...
INSTALLED_APPS = [
...
# Rest framework
'rest_framework',
'rest_framework.authtoken',
'myApp',
]
...
REST_FRAMEWORK = {
# other settings...
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
I want auth with token.
I successfully issued token.
POST '...api/user_auth/' {
"username": "test",
"password": "blahbalh123"
}
{
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjIwMTMyMzA2Iiwib3JpZ19pYXQiOjE1MDk5NzA5NjcsInVzZXJfaWQiOjMsImVtYWlsIjoiaW50ZXJydXBpbmdAbmF2ZXIuY29tIiwiZXhwIjoxNTA5OTcxNTY3fQ.acwqAP4sBPZWYPC0GfgL3AZarNz4Opb_5P4RewZJYrI"
}
but I fail Auth with Token
Request:
POST ...api/lecture/create/ HTTP/1.1
Host: 127.0.0.1:8000
Authorization: Token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjIwMTMyMzA2Iiwib3JpZ19pYXQiOjE1MDk5NzA5NjcsInVzZXJfaWQiOjMsImVtYWlsIjoiaW50ZXJydXBpbmdAbmF2ZXIuY29tIiwiZXhwIjoxNTA5OTcxNTY3fQ.acwqAP4sBPZWYPC0GfgL3AZarNz4Opb_5P4RewZJYrI
Response:
Status: 401 Unauthorized
Allow →GET, POST, HEAD, OPTIONS
Content-Length →27
Content-Type →application/json
Date →Mon, 06 Nov 2017 12:59:17 GMT
Server →WSGIServer/0.1 Python/2.7.13
Vary →Accept
WWW-Authenticate →Token
X-Frame-Options →SAMEORIGIN
{
"detail": "Invalid token."
}
What's wrong with my code?
sorry for my english skill.

I think you are mixing the Tokens from django-rest-framework and REST framework JWT.
In the DJR documentations says:
from rest_framework.authtoken import views
urlpatterns += [
url(r'^api-token-auth/', views.obtain_auth_token)
]
You should replace your code with:
from rest_framework.authtoken import views
from .views import LectureCreateView
urlpatterns = [
...
url(r'^api/user_auth/$', views.obtain_auth_token),
url(r'^api/lecture/create/$', LectureCreateView.as_view()),
]
I hope it can help you.

Related

rest_framework_swagger installation - HTTP 401 Unauthorized

I have installed rest_framework_swagger successfully, after that I set url in urls.py file project:
from django.contrib import admin
from django.urls import path, include, re_path
from unimiproject.router import router
from rest_framework.authtoken import views
from rest_framework.schemas import get_schema_view
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
re_path(r"^appjud/",include("appjud.urls")),
path('api/', include(router.urls)),
path('api-token-auth/', views.obtain_auth_token, name='api-token-auth'),
path('openapi/', get_schema_view(
title="School Service",
description="API developers hpoing to use our service"
), name='openapi-schema'),
path('docs/', TemplateView.as_view(
template_name='documentation.html',
extra_context={'schema_url':'openapi-schema'}
), name='swagger-ui')
]
but if I browse http://172.18.0.1:7000/openapi/ I get this:
Schema
GET /openapi/
HTTP 401 Unauthorized
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
WWW-Authenticate: Token
{
"detail": "Authentication credentials were not provided."
}
Why do I get "Authentication credentials were not provided"? It should show me schema of all apis not to test they.
Try using permission_classes=(permissions.AllowAny,) to your code
then the user not needed a username and password to assess your documentation
from rest_framework import permissions
from drf_yasg import openapi
path('openapi/',get_schema_view(
openapi.Info(
title="School Service",
description="API developers hoping to use our service",
contact=openapi.Contact(email="mail#domain.com"),
license=openapi.License(name="Proprietary Software"),
),
public=True,
permission_classes=(permissions.AllowAny,),
))

using django permissions.IsAuthenticatedOrReadOnly with token authentication

I have this Django API view that I want to allow authorized and unauthorized users access it, I have set Django token-authentication as the default authentication class, however, whenever I try to access the view as unauthenticated user,I get error Unauthorized: which is weird coz am making a get request in the view
my code is here
#api_view(['GET'])
#permission_classes([permissions.IsAuthenticatedOrReadOnly])
def all_Search(request):
print(request.headers)
src = request.GET.get('q')
my settings for rest framework is
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}
is there a way to work around this? will appreciate any help, thanks
I've tried to reproduce your error but I failed.
This is my configuration:
settings.py
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken'
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}
urls.py
urlpatterns = [
path('search/', api.all_search, name="search")
]
api.py
from rest_framework import permissions
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
#api_view(['GET'])
#permission_classes([permissions.IsAuthenticatedOrReadOnly])
def all_Search(request):
print(request.headers)
src = request.GET.get('q')
return Response()
test.py
from rest_framework import status
from rest_framework.test import APILiveServerTestCase
from rest_framework.reverse import reverse
class TestTokenAuthorization(APILiveServerTestCase):
def test_can_search_without_token(self):
url = reverse('search', kwargs={})
response = self.client.get(url, {}, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
and this is the result of the test:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
{'Cookie': '', 'Content-Type': 'application/octet-stream'}
Destroying test database for alias 'default'...
I'm using djangorestframework==3.10.3 and python3.7
As you can see, I didn't authenticate the request (no token is passed) and the headers were printed as expected from the permissions.
Maybe your issue is caused by something else in your code. Try to include more details in your question.
By the way, your all_Search function is missing the return Response()
Okey I just decided to try something and it seams to be working, at least for now. I somehow believed that DEFAULT_AUTHENTICATION_CLASSES was the issue in this case and in deed it was, so I had to just remove the
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}
#opt to use
#authentication_classes = [TokenAuthentication, SessionAuthentication]
#in my views that requires authentications
in my settings, this was not all though, but now I could access the view either authorized or not: (having auth token or not). but this was not getting authenticated user by default
so I did this
make a view to get a user based on a given token
from django.contrib.auth.models import AnonymousUser
from rest_framework.authtoken.models import Token
def get_user(token):
try:
token = Token.objects.select_related('user').get(key=token)
return token.user
except:
return AnonymousUser
and get user in my view if token exists in the headers
#api_view(['GET'])
#permission_classes([permissions.IsAuthenticatedOrReadOnly])
def all_Search(request):
auth = request.headers.get('Authorization').split(' ')[1]
key = request.headers.get('Authorization').split(' ')[0]
if key == 'Token' and auth != 'null': #used null coz my frontend sends null if key is not available
user = get_user(auth)
print(user)

Authentication credentials were not provided drf

when i trying to access api i'm getting this error:
"detail": "Authentication credentials were not provided."
i have included this in settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':(
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES':(
'rest_framework.permissions.IsAuthenticated',
)
}
my app api urls.py:
from django.urls import path,include
from . import views
from rest_framework import routers
router = routers.SimpleRouter()
router.register(r'',views.UserViewSet, 'user_list')
urlpatterns = router.urls
my views.py:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.object.all()
serializer_class = serializers.UserSerializers
serializers.py:
from rest_framework import serializers
from users.models import User
class UserSerializers(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email','password')
my main urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('',include(urls)),
path ('', include(user_urls)),
path('api/',include(api_urls)),
when i running localhost:8000/api i'm getting the error
You can't access the api from the browsers url if you are using TokenAuthentication.
as said by #DarkOrb TokenAuthentication expects a authorization header with token as it's value.
So You must pass token whenever you call the api.
You can test your api using postman.
In above image i have passed token in headers of postman to access my api.
When you call your api from frontend side,pass your token along with the request.
If you just want to use your api in only desktop's browser,in that case you can use SessionAuthentication only.For mobile devices Tokenauthentication must be done.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':(
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES':(
'rest_framework.permissions.IsAuthenticated',
)
}
use this in your settings.py file, what is happening is that rest_framework.authentication.TokenAuthentication expects a authorization header with token as it's value, but you can't send that with your browser, to browse API from browser you must have SessionAuthentication enabled.

Authentication credentials were not provided with Django Rest Framework JWT

I am having trouble implementing token authentication with JWT in the Django rest framework with a Typscript frontend. I'm getting
{detail: "Authentication credentials were not provided."}
with my API call via Typescript, which is:
readonly BASE_URL = 'http://127.0.0.1:8000/'
api_url = this.BASE_URL + 'items/'
auth_url = this.BASE_URL + "api-token-auth/"
getItemsService(token) {
const headers = new HttpHeaders()
headers.append('Content-Type', 'application/json')
headers.append('Authorization', 'JWT ' + token.token)
return this.http.get(this.api_url, {headers: headers})
}
Logging in works fine. It's when I try to load the items that I have issues.
Here's my Django code:
views.py
from rest_framework import generics
from .models import Item
from .serializers import ItemSerializer
class ItemList(generics.ListCreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
class ItemDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
items/urls.py
from django.urls import path
from .views import ItemList, ItemDetail
urlpatterns = [
path('', ItemList.as_view()),
path('<int:pk>/', ItemDetail.as_view()),
]
project/urls.py
from django.contrib import admin
from django.urls import include, path
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path('items/', include('groceries.urls')),
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
path('api-token-auth/', obtain_jwt_token),
]
settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
I thought the issue would have to be with Django, but I am able to get what I expect with
curl -H "Authorization: JWT <token>" http://localhost:8000/items/
If my backend was not set up correctly, this wouldn't work. So it must be my frontend code.
Based on what you described, It may be a CORS issue. Because you have access to your api endpoint via curl command. But not with browser.
Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin. A web application makes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, and port) than its own origin.
I checked your Angular typescript code, It seems fine. I suggest to follow below instructions in your django project and see how it goes:
1) install it for pip via pip install django-cors-headers command.
2) In settings.py file, add this app to your installed apps:
INSTALLED_APPS = (
...
'corsheaders',
...
)
3) You will also need to add a middleware class to listen in on responses:
MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
remember CorsMiddleware should be placed as high as possible.
4) Add this line to your settings.py file.
CORS_ORIGIN_ALLOW_ALL = True
for full documentation refer to django-cors-headers.

django-rest-framework login via Ajax returns HTML

I'm using the django-rest-framework and trying to login using Ajax, but the login API is returning HTML instead of JSON.
My configs:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
)
}
And the Ajax call:
$.ajax({
url: '/api-auth/login/',
method: 'POST',
data: "username=xxxxx&password=123",
headers: {
Accept: 'application/json'
},
success: function(resp) {
console.log(resp);
},
error: function(resp) {
console.error(resp);
}
});
Even if I'm specifying the Accept header, it always returns text/html.
Am I using the wrong endpoint?
I'm using JSONWebToken for external clients (ie, mobile) and the SessionAuthentication for same domain web requests. I expect the SessionAuthentication to set the cookie I can use to make further requests once logged in. If the login fails, I expect the API to return the error in JSON (ie, "Invalid username and password").
urls.py (important parts)
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = [
url(r'^admin/', admin.site.urls),
...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api-token-auth/', obtain_jwt_token),
url(r'^api/', include(router.urls)),
]
Using:
Django==1.11
djangorestframework==3.7.7
djangorestframework-jwt==1.11.0
If you want to set a http only cookie you just have to add the parameter 'JWT_AUTH_COOKIE': 'you_cookie_name', inside the dictionary JWT_AUTH in settings.py also remember use the view that provide django_rest_framework_jwt located in from rest_framework_jwt.views import obtain_jwt_token in your case api-token-auth/'