JWT configuration in Django - django

I'm developing a Django application for Windows with Pyhton 2.7.15. I need to implement an authentication mechanism where if a user has a specific JWT token, he can browse the application (in other words, I just need to verify the token and not generate it). The token is very easy and maybe will be something like this:
Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
{
"iss": "customIssuer"
}
Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
To implement the verification's service, I installed the Rest framework JWT tools and I modifyed my setting.py in this way:
...
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.TokenAuthentication'
),
}
JWT_AUTH = {
'JWT_ISSUER': 'customIssuer'
}
...
then I modifyed the urls.py:
...
from rest_framework_jwt.views import verify_jwt_token
urlpatterns = [
...
url(r'^api-token-verify/', verify_jwt_token),
...
]
Finally, using Postman, I tryed to send a POST request with the above token but I get a 400 Bad Error error with this body:
{
"non_field_errors": [
"Invalid payload."
]
}
Investigating about the reason I realize that I must add the username claim in the payload but I don't want to. It's possible to configure the application to ignore that claim?

Related

How to add password and username pop up for Django Swagger?

I am using drf-yasg library for the Django Swagger. I need to add the authentication on username and password level. There are three security schemes available in this library "basic", "apiKey" or "oauth2".
Is there any way I can set my credentials for swagger in my django project settings and authenticate the swagger apidocs based on that?
To have the popup for authentication in 'DRF' and also in 'SWAGGER' panel, simply add these lines of code which I arrowed to your settings.py:
'DRF' implementation
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
# the link you can read about
# https://stackoverflow.com/questions/51906745/django-rest-framework-logout-not-working-after-token-authentication
'rest_framework.authentication.BasicAuthentication', # <<--
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}
In REST_FRAMEWORK, inside the DEFAULT_AUTHENTICATION_CLASSES, (which is a list) add the
rest_framework.authentication.BasicAuthentication.
It tells the djagno to authenticate using the default authentication that djagno provides.
'SWAGGER' implementation
If you want to use it in 'SWAGGER' as well, do the below:
In SWAGGER_SETTINGS, inside the SECURITY_DEFINITIONS which is a dict, add these lines of code to implement that:
'basic': {
'type': 'basic'
},
Default 'swagger' settings would be like this:
SWAGGER_SETTINGS = {
'DOC_EXPANSION': 'list',
'APIS_SORTER': 'alpha',
'USE_SESSION_AUTH': False,
'SECURITY_DEFINITIONS': {
'Bearer': { # <<-- is for JWT access token
'type': 'apiKey',
'name': 'Authorization',
'in': 'header'
},
'basic': { # <<-- is for djagno authentication
'type': 'basic'
},
},
}
Attention that Bearer is for JWT access token. basic is for djagno authentication.
Thant you for reading!

"detail": "No active account found with the given credentials" simplejwt

I am using Django rest API and trying to authenticate a user with username and password (obtain token pairs) with simpleJWT. In my settings.py I have added
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
}
my urls.py is as below
urlpatterns = [
path('admin/', admin.site.urls),
path('api/token/', TokenObtainPairView.as_view(), name ='token_obtain_pair'),
path('api/token/refresh/', jwt_views.TokenRefreshView.as_view(), name ='token_refresh'),
]
However when I send a request to authenticate (register) a user and obtain token for that user it seems like it tries to verify the user instead and gives me the following error
{
"detail": "No active account found with the given credentials"
}
I have read multiple other related questions but nothing helped. What should I do to obtain a token for an email address and password?

Django Rest Framework : Authentication credentials were not provided

Images in the current database have one piece of data.
But, I am currently experiencing the following error
"GET /images/all/ HTTP/1.1" 401 58"
"detail": "Authentication credentials were not provided."
My Git Hub URL : https://github.com/Nomadcoders-Study/Nomadgram
Which part of the setup went wrong?
I saw your Github project settings.py file.
This error is because you are using IsAuthenticated backend for all of your requests to Rest APIs. Also you setup jwt authorization system:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
So basically, if you want to create a request to any of your API endpoints, you should provide jwt token authorization header in it. like this for:
curl "<your api endpoint>" -H "Authorization: jwt <token_received>"
Also remember to setup and API to receive token from it, by providing username and password in serializer.
try this in your settings file
settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_simplejwt.authentication.JWTAuthentication',),
}
You can add it to your project Settings rest_framework configuration
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES'('rest_framework.authentication.BasicAuthentication', ),
}

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/'

Django REST Swagger with OAuth2 authentication

I have a REST API created with Django rest framework. To authenticate my API calls I am using OAuth2 tokens. My question is how can I enable standard username/password authentication in docs generated by Django rest swagger.
Right now i am gettings
401 : {"detail":"Authentication credentials were not provided."} http://127.0.0.1:8000/docs/?format=openapi
settings
REST_FRAMEWORK = {
# Don't perform any authentication on API calls so we don't have any CSRF problems
# :PRODUCTION: Put back authentication for production version when not testing on same server?
'DEFAULT_AUTHENTICATION_CLASSES': [
'oauth2_provider.ext.rest_framework.OAuth2Authentication',
'rest_framework_social_oauth2.authentication.SocialAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'PAGE_SIZE': 1000, # Max number of results returned from a list API call
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
# Use JSONRender so the Web API interface is not shown. This is needed when testing the app on the same server
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
)
}
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'veeu': {
'type': 'oauth2',
'flow': 'password',
'tokenUrl': 'http://localhost:8000/auth/token/',
'scopes': {
'write:all': 'Write all',
'read:all': 'Read all',
}
}
},
}
LOGIN_URL = 'http://localhost:8000/admin/'
When I click Django login it takes me to admin login page. And after I log in, this message is still the same. If I add header Authorization: Bearer TokenHere it works. However, the point is to enable username/password login.
To access Swagger documentation, you need SessionAuth with the following in the settings.py :
# API VERSIONING
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated'
],
}
This allows you to access Swagger generated documentation. Problem is, whatever endpoint you have protected with OAuth2 won't be visible via Swagger, at least if you are generating OAuth via "application". The following code does not work at all and I'm linking the thread discussed asking for anyone to work on that feature:
# TODO Swagger implementation is not working for password since
# it sends client_id and client_secret as query strings and not as
# user separated with "::"
# The "application" flow setting also that does work
#
SWAGGER_SETTINGS = {
'SUPPORTED_SUBMIT_METHODS': [], # Due to bug described above
'SECURITY_DEFINITIONS': {
"customers_auth": {
"type": "oauth2",
"tokenUrl": "/o/token/",
"flow": "password",
"scopes": {
"read": "Read scope",
"write": "Write scope"
}
}
},
}