DRF - Authentication credentials were not provided - django

I am testing django rest framework using python requests module but its says an error. I am just beginner rest-api developer.
DRF setting main.py
import datetime
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
# 'rest_framework.authentication.BasicAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
)
}
JWT_AUTH = {
'JWT_ENCODE_HANDLER':
'rest_framework_jwt.utils.jwt_encode_handler',
'JWT_DECODE_HANDLER':
'rest_framework_jwt.utils.jwt_decode_handler',
'JWT_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_payload_handler',
'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
'JWT_RESPONSE_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_response_payload_handler',
'JWT_ALLOW_REFRESH': False,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
'JWT_AUTH_HEADER_PREFIX': 'JWT', # Authorization: JWT <token>
'JWT_AUTH_COOKIE': None,
}
and my testing code is
import os
import json
import requests
AUTH_ENDPOINT = 'http://127.0.0.1:8000/api/auth/jwt/'
ENDPOINT = 'http://127.0.0.1:8000/api/status/'
image_path = os.path.join(os.getcwd(), 'drf.png')
headers = {
"Content-Type": "application/json"
}
data = {
"username": 'jaki',
"password": 'SADHIN101119'
}
r = requests.post(AUTH_ENDPOINT, data=json.dumps(data), headers=headers)
token = r.json()['token']
headers = {
"Content-Type": "application/json",
"Authorization": "JWT" + token
}
post_data = json.dumps({"content": "some random content"})
posted_response = requests.post(ENDPOINT, data=post_data, headers=headers)
print(posted_response.text)
Error showing
{"detail":"Authentication credentials were not provided."}
How can i solve the problem. Thanks.

In the Authorization header, the JWT prefix and token must be separated with a space. Change your Authorization header to:
"Authorization": "JWT " + token

This a a hunch ... but uncomment out
# 'rest_framework.authentication.BasicAuthentication'
When you're trying to get your Token, you're using BasicAuth to send over your login creds. That's probably failing.

Related

Problem importing a dashboard: The response shows a login page

When I use the Superset's API to import a dashboard the response shows me a login page.
I am doing the request using Python.
import requests
headers = {
'accept': 'application/json',
'Authorization': f'Bearer {jwt_token}',
'X-CSRFToken': csrf_token,
'Referer': url
}
files = {
'formData': (
dashboard_path,
open(dashboard_path, 'rb'),
'application/json'
)
}
response = requests.get(url, files=files, headers=headers)
Does anyone know how to solve this problem?
I had some trouble with the Superset API myself, mostly because I did not handle the CSRF Token correctly:
It seems to be important that the retrieval of the JWT Token, the CSRF Token and the actual request happen in the same session.
If I don't do that, I can reproduce your error and are also sent to the login page (also you use a GET request in this example, but it should be POST).
Here an example from my local test-setup:
import requests
session = requests.session()
jwt_token = session.post(
url='http://localhost:8088/api/v1/security/login',
json={
"username": "admin",
"password": "admin",
"refresh": False,
"provider": "db"
}
).json()["access_token"]
csrf_token = session.get(
url='http://localhost:8088/api/v1/security/csrf_token/',
headers={
'Authorization': f'Bearer {jwt_token}',
}
).json()["result"]
headers = {
'accept': 'application/json',
'Authorization': f'Bearer {jwt_token}',
'X-CSRFToken': csrf_token,
}
response = requests.post(
'http://localhost:8088/api/v1/dashboard/import',
headers=headers,
files={
"formData": ('dashboards.json', open("dashboards.json", "rb"), 'application/json')
},
)
session.close()

Django REST JSONWebTokenAuthentication + Angular (Authorization details not provided)

For a couple of days i've been trying to get this rather simple authentication setup to work.
I'm using the Django REST plugin 'django-rest-framework-jwt' to do JSON web token authentication.
When CURLing the API, it works as supposed.
Though, when issuing the requests through my Angular application; i'm constantly getting an Unauthorized error with the details 'Authorization details not provided'. However, when crawling the requests, one can clearly see that it is present (the token within the request is valid, as i've used it within the CURL':
I'm injecting the authentication header via a interceptor I wrote; which looks like this:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.session.authorization;
if (!auth) {
return next.handle(req);
} else {
const newReq = req.clone({
setHeaders: {
Authorization: auth,
},
});
return next.handle(newReq);
}
}
Further, the settings of the JWT_AUTH settings are defined as follows:
JWT_AUTH = {
'JWT_ENCODE_HANDLER':
'rest_framework_jwt.utils.jwt_encode_handler',
'JWT_DECODE_HANDLER':
'rest_framework_jwt.utils.jwt_decode_handler',
'JWT_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_payload_handler',
'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
'JWT_RESPONSE_PAYLOAD_HANDLER':
'auth.views.jwt_response_payload_handler',
'JWT_SECRET_KEY': SECRET_KEY,
'JWT_GET_USER_SECRET_KEY': None,
'JWT_PUBLIC_KEY': None,
'JWT_PRIVATE_KEY': None,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_LEEWAY': 0,
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
'JWT_AUDIENCE': None,
'JWT_ISSUER': None,
'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(seconds=3600),
'JWT_AUTH_HEADER_PREFIX': 'Bearer',
'JWT_AUTH_COOKIE': None,
}
The framework settings are as follows:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
Any suggestions on this? I'm not sure whats going on here.
EDIT
Request/response headers in the network tab:
So, end it had nothing to do with the Angular app, but the sever not accepting CORS. Fix it by the explanation in the following post:
https://www.techiediaries.com/django-cors/

Authentication credentials were not provided django-rest-auth

I have an application which I implemented django restframework and django reat-auth and jango framework jwt. I followed the instructions and every thing works fine in the browser. I now decided to test out the connection in postman and trying to get the logged in user's details which the endpoint is /rest-auth/user but i get the following error
{
"detail": "Authentication credentials were not provided."
}
and I decided to copy the returned Token and put it in the header of the user url as
"Authorization": "Token ahagjbeghq7hbcvgqhvwqu08hevug.jwhhwiiwhw",
"Content-Type": "application/json; charset=utf-8"
after modifying the header with the returned token I expected it to display the user's details but instead I still got
{
"detail": "Authentication credentials were not provided."
}
but I can verify that the token is correct through the url provided by the restframework jwt
/api-token-verify which retuns the token value back. this is my django rest authentication classes
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
),
}
You should use JWT instead of Token inside Authorization header for jwt token:
"Authorization: JWT <your_token>"
As #neverwalkaloner mentioned already JWT keyword suppose to be the value of Authorization in the header section of Postman. Docs
Additionally, if you don't want JWT as a keyword in with your token, you can customize it from your settings: with following key: JWT_AUTH_HEADER_PREFIX
JWT_AUTH = {
'JWT_ENCODE_HANDLER':
'rest_framework_jwt.utils.jwt_encode_handler',
'JWT_DECODE_HANDLER':
'rest_framework_jwt.utils.jwt_decode_handler',
'JWT_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_payload_handler',
'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
'JWT_RESPONSE_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_response_payload_handler',
'JWT_SECRET_KEY': settings.SECRET_KEY,
'JWT_GET_USER_SECRET_KEY': None,
'JWT_PUBLIC_KEY': None,
'JWT_PRIVATE_KEY': None,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_LEEWAY': 0,
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_AUDIENCE': None,
'JWT_ISSUER': None,
'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
'JWT_AUTH_HEADER_PREFIX': 'Bearer', #this most commonly accepted way
'JWT_AUTH_COOKIE': None,
}

Pass username and password with angular 5 http request to django rest api

am integrating django rest api with angular 5. Django rest framework implements it's basic auth as
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
}
Am able to hit api with postman by providing django superuser (username and password) in Headers menu but when i hit api from angular it retruning 401. I have tried multiple solutions but not getting perfect solution
here is what i am trying
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Username': <username>,
'Password': <password>
})
};
return this.http.get(url, this.httpOptions)
.toPromise()
.then(res=>{
return res;
});
Also tried headers as
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa('<username>:<password>')
})
};

how to add token auth to swagger + django rest framework?

I am using both great tools DRF and Django-REST-Swagger, however a few of my API views are under token authentication.
So now I'd like to add to my swagger doc page of my API the possibility to test those token auth api urls, including the Token header. How could I do this?.
A snapshot of my class API view is like this:
class BookList(APIView):
"""
List all books, or create a new book.
"""
authentication_classes = (TokenAuthentication, )
permission_classes = (IsAuthenticated,)
...
Since Swagger auto detects a lot of stuff, I was expecting to notice about token auth, and ask me about token or user id in its web interface, but it doesn't. Hence I am testing it manually through CURL commands...
If you're using token authentication, you might want to look at this question
Basically, you just need to add this to your settings.py:
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'api_key': {
'type': 'apiKey',
'in': 'header',
'name': 'Authorization'
}
},
}
In your Swagger UI page you should see an Authorize button. Click that and enter your Authorization value in the input text field.
I answer myself since I made it work.
Actually Swagger settings has an option for this, api_key ->
SWAGGER_SETTINGS = {
"exclude_namespaces": [], # List URL namespaces to ignore
"api_version": '0.1', # Specify your API's version
"api_path": "/", # Specify the path to your API not a root level
"enabled_methods": [ # Specify which methods to enable in Swagger UI
'get',
'post',
'put',
'patch',
'delete'
],
"api_key": '', # An API key
"is_authenticated": False, # Set to True to enforce user authentication,
"is_superuser": False, # Set to True to enforce admin only access
}
To me it wasn't that clear, but I've just input a valid token for testing user and it worked for the auth needed views :-)
My Problem was that after activating TokenAuthentification my api urls were not shown any more in the swagger UI due to an AuthentificationError.
For me the solution was to activate both authentaction classes in the Django Rest Framework Settings:
SessionAuthentification -> for the Swagger UI
TokenAuthentification -> for the Rest Clients
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication'
)
}
The schema view needs to have the permission of AllowAny. This allows the plugin to see which endpoints are available before the user has authenticated. The end points should still be protected if they are setup correctly. Example:
#api_view()
#renderer_classes([SwaggerUIRenderer, OpenAPIRenderer, renderers.CoreJSONRenderer])
#authentication_classes((TokenAuthentication, SessionAuthentication))
#permission_classes((AllowAny,))
def schema_view(request):
generator = schemas.SchemaGenerator(
title='My API end points',
patterns=my_urls,
url="/api/v1/")
return response.Response(generator.get_schema(request=request))
It is best to remove the SessionAuthentication and only use the TokenAuthentication but that is a matter of choice, here I have removed it
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated'
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication'
)
Be sure it add 'rest_framework.authtoken' into your installed apps and remove the CsrfViewMiddleware from the middleware classes as it will no longer be needed. And the swagger settings
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'api_key': {
'type': 'apiKey',
'in': 'header',
'name': 'Authorization'
}
},
'USE_SESSION_AUTH': False,
'JSON_EDITOR': True,
}
This will make swagger populate the token into all of the example curl commands as well, which is really nice to have. Leaving the session auth in place seems to disable this.
The swagger authorization dialog asks for the api_key which needs to be provided. Can not seem improve this, will update this post if I do.
just add to you rest framework setting SessionAuthentication should be at the top
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'mymodule.authentication.CustomeAuthentication',
)
Note: SessionAuthentication will use your Django login session
CustomeAuthentication will be used for rest api for real use case.
if you are implementing the answer of #Melvic Ybanez with django-rest-swagger==2.2.0 and still doesn't work. Downgrade to django-rest-swagger==2.1.2.
Button authorize should work now.
I manage to change Swagger's default basic authentication to token authentication with this configuration but when try me button is pressed rest swagger accepts any authentication regardless of valid token.
Also note, when I added SessionAuthentication to my REST_FRAMEWORK in my settings.py, my api failed to be displayed on swagger docs.
django-rest-swagger==2.2.0
djangorestframework==3.7.7
settings.py
INSTALLED_APPS = [
'rest_framework',
'rest_framework_swagger',
'rest_framework.authtoken',
]
REST_FRAMEWORK = {
# Parser classes priority-wise for Swagger
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
'rest_framework.parsers.JSONParser',
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
)
}
# SWAGGER SETTINGS
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'api_Key': {
'type': 'apiKey',
'in': 'header',
'name': 'Token Authorization'
}
},
}
some helpful documentation https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-definitions-object
Please use rest_framework_jwt.authentication.JSONWebTokenAuthentication instead of rest_framework.authentication.TokenAuthentication.
My code is
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
# 'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
'rest_framework.parsers.JSONParser',
),
}
AUTH_USER_MODEL = 'auth.User'
JWT_AUTH = {
'JWT_ENCODE_HANDLER':
'rest_framework_jwt.utils.jwt_encode_handler',
'JWT_DECODE_HANDLER':
'rest_framework_jwt.utils.jwt_decode_handler',
'JWT_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_payload_handler',
'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
'JWT_RESPONSE_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_response_payload_handler',
'JWT_SECRET_KEY': SECRET_KEY,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_LEEWAY': 0,
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=86400),
'JWT_AUDIENCE': None,
'JWT_ISSUER': None,
'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_AUTH_HEADER_PREFIX': 'Bearer',
}
SWAGGER_SETTINGS = {
'SHOW_REQUEST_HEADERS': True,
'SECURITY_DEFINITIONS': {
'Bearer': {
'type': 'apiKey',
'name': 'Authorization',
'in': 'header'
}
},
'USE_SESSION_AUTH': False,
'JSON_EDITOR': True,
'SUPPORTED_SUBMIT_METHODS': [
'get',
'post',
'put',
'delete',
'patch'
],
}
I solved the problem.