How to add custom Header in Authlib on Django - python

I would need some of your help adapting Authlib with Django.
I'm trying to develop a Django app using OpenId and Authlib to connect my users and facing an issue with the access token, the issue invalid_client occurs. Using Postman I found out that the OpenId provider needs some parameters in the Header like 'Content-Length' or 'Host'.
When the Header param is defined in client.py, it works like a charm. However, I'd like to pass the custom header from views.py (mostly to avoid defining the Host directly in the package), but authorize_access_token doesn't allow multiple arguments,
def auth(request):
token = oauth.customprovider.authorize_access_token(request)
Maybe the "Compliance Fix for non Standard" feature might help, but I wasn't able to adapt it for Django and the Header parameter
https://docs.authlib.org/en/stable/client/oauth2.html#compliance-fix-oauth2
from authlib.common.urls import add_params_to_uri, url_decode
def _non_compliant_param_name(url, headers, data):
params = {'site': 'stackoverflow'}
url = add_params_to_uri(url, params)
return url, headers, body
def _fix_token_response(resp):
data = dict(url_decode(resp.text))
data['token_type'] = 'Bearer'
data['expires_in'] = int(data['expires'])
resp.json = lambda: data
return resp
session.register_compliance_hook(
'protected_request', _non_compliant_param_name)
session.register_compliance_hook(
'access_token_response', _fix_token_response)
Does anyone know a way to pass a custom Header to Authlib or defining it using the Compliance Fix and Django?

I had to do this recently for a provider that required an Authorization header added to the the refresh token. Here is the code I used.
Add the register_compliance_hook inside the function that is called using the compliance_fix argument when initializing the service.
def _compliance_fixes(session):
def _add_header_refresh(url, headers, body):
headers.update({'Authorization': "Basic " + self.secret_client_key})
return url, headers, body
session.register_compliance_hook('refresh_token_request', _add_header_refresh)
oauth = OAuth()
oauth.register("oauth-service", compliance_fix=_compliance_fixes)

Related

How to add header when we writing test cases in django rest framework?

I'm trying to write test cases for my project. Now the problem is, that I don't figure out how to pass custom keyword arguments in the header. Here's my test case class below.
class ProjectTestClass(APITestCase,URLPatternsTestCase):
allow_database_queries: True
def projects_notifications_list(self,token,project_key):
url = reverse('projects:project_noti_list',kwargs={"category": "all"})
response = self.client.get(
url,
format='json',
HTTP_AUTHORIZATION="JWT "+token,
headers={"platform-subscriber-id":project_key}
)
print("data -> ",response.data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(len(response.data), 3)
as you can see I'm passing plaform-subsciber-id in the header. but getting an error that {'message': 'Platform subscriber id is required in header'}. It seems like id is not properly configured in the header. Does anybody know this?
This is how you update headers in tests:
headers = {'platform-subscriber-id': project_key}
self.client.credentials(**headers)
DRF docs say: The credentials method can be used to set headers that will then be included on all subsequent requests by the test client.

How can i get Bearer token using basic authentication using python?

I want to get an authorization token using basic authorization. I send a post request using my user name and password but to get the token a body data which is raw text grant_type=client_credentials&scope=Dashboard must contain in the request. but I cannot send the grant_type=client_credentials&scope=Dashboard body data in the post request using python.
#task(1)
def login(self):
self.client.post("/OAuth/Token/", {'Username':'abc', 'Password':'12345'})
self.client.post() returns a Response object. You can see the api at https://requests.readthedocs.io/en/latest/api/#requests.Response
To read out something in the response you can try something like
#task(1)
def login(self):
res = self.client.post("/OAuth/Token/", {'Username':'abc', 'Password':'12345'})
token = res.json()['token']
This attempts to process the Response body as json and pull out the token field. If this doesn't work please provide details on what you are seeing in the response.
Please try this:
In the URL, Append the Grant type and Scope as shown below:
/OAuth/Token?grant_type=client_credentials&scope=Dashboard
It will look like this
self.client.post("/OAuth/Token?grant_type=client_credentials&scope=Dashboard", {'Username':'abc', 'Password':'12345'})

Django REST authentication from desktop app

I have been trying to use the Django-REST authentication to validate the user name /password given in a desktop app.
On the server side, I have installed the following DJANGO-REST-FRAMEWORK-JWT package found here:
https://github.com/GetBlimp/django-rest-framework-jwt
I have gone through the example and when I run the following on the command line get a token as a response:
curl -X POST -d "username=luca&password=letmein123" http://localhost:8000/api-token-auth/
And I get:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InBhbmthaiIsInVzZXJfaWQiOjIsImVtYWlsIjoiIiwiZXhwIjoxNDc5MTE5NzQ2fQ.RA085m-YSnGFheykCCxSVxI_9rW9AC9kEaOkUB5Gm0A"}
I tried something like:
import requests
resp = requests.post('http://127.0.0.1:8000/api-token-auth/', data={}, auth=('luca', 'letmein123'))
However, this always returns response code 400 with Bad request
My question is how can I do that from my desktop python app. I basically want to call the same API with the username and passord and be able to process the response and access protected APIs.
The auth parameter of requests.request is by default meant for Basic/Digest/Custom HTTP Auth, analogous to the -u, --user <user:password> parameter of curl.
You could define your own custom Authentication class to achieve the desired result, but the basic way to achieve the same result as your original curl request is:
resp = requests.post(
'http://localhost:8000/api-token-auth/',
data={"username": "luca", "password": "letmein123"})
The data dictionary can alternatively be supplied as json by using the json parameter if you prefer (the request would be different, but also supported by Django REST framework JWT).
You can then use the token (extracted with token = resp.json()['token']) to access the restricted urls as following:
requests.post(
'http://localhost:8000/some-personal-function/',
json={"foo": 42},
headers={'Authorization': 'JWT ' + token})
By the way looking at response.text might help finding the reason, which would, in the case of your 400 response, contain the following:
'{"username":["This field is required."],"password":["This field is required."]}'

Setting HTTP User-Agent header with requests-oauthlib

I'm using the requests-oauthlib library to get a request token from an OAuth (v1) provider.
oauth = OAuth1Session(CONSUMER_KEY, client_secret=CONSUMER_SECRET,
signature_method=SIGNATURE_HMAC,
signature_type=SIGNATURE_TYPE_AUTH_HEADER)
resp = oauth.fetch_request_token(url=REQUEST_TOKEN_URL)
I'd like to send a custom User-Agent header with the request token fetch request and include some contact information in case there are ever any problems with my script. Can this be done?
It's possible to pass in a client class to the OAuth1Session constructor. From the docblock in the relevant file:
"""
:param client_class: A subclass of `oauthlib.oauth1.Client` to use with
`requests_oauthlib.OAuth1` instead of the default
"""
Within the oauthlib.oauth1.Client class, the _render(self, request, formencode=False, realm=None) method appears responsible for preparing the request. Since unrelated headers don't impact the base string that the request signature is created from, adding a new header/changing an existing User-Agent header shouldn't cause the signature to change in any way.
As such, we can create a custom client class, override the _render method and call the implementation in the parent class once we've added our header:
class CustomClient(Client):
def _render(self, request, formencode=False, realm=None):
request.headers['User-Agent'] = "FooClient/1.0"
return super()._render(request, formencode, realm)
The code that instantiates OAuth1Session then simply needs to reference the above class:
oauth = OAuth1Session(CONSUMER_KEY, client_secret=CONSUMER_SECRET,
signature_method=SIGNATURE_HMAC,
signature_type=SIGNATURE_TYPE_AUTH_HEADER, client_class=CustomClient)

Create Facebook Event with python's urllib2 library

I'm trying to create an event with facebook from an external application. I've read this con events, where it states that you can create an event via POST, so i have the following-
data = dict()
data['access_token'] = self.access_token
data['name'] = 'Fb event from Python!'
data['start_time'] = datetime.datetime.now().isoformat()
data = urllib.urlencode(data)
url = 'https://graph.facebook.com/me/events'
request = urllib2.Request(url=url, data=data)
response = urllib2.urlopen(request)
Where I already have my access token and my fb permissions set so my app can create events and so forth. But I get an error 400 = Bad Request, so if anyone could help I'd be more than happy thanks in advance
Well I would say you should think about using facebook-sdk. From your error i.e http 400 you know that what you are doing wrong is how you are sending the http request itself. The request requires certain parameters in a certain form that you are not giving. If you look at
the request function in here
It makes the request in this form where path is id( I am also not sure me is valid here, but perhaps we can use me for the resource whose access-token we are using)
I think args access token .
file = urllib2.urlopen("https://graph.facebook.com/" + path + "?" +
urllib.urlencode(args),
post_data, timeout=self.timeout)
Thus change the form in which you are making the request. You can go through facebook.py's code and docs to figure out the variables mean based on your needs

Categories