Bearer Token extraction from request django - python

If I have a post request with this JSON :
{
"user_id":230,
"name":"Anthony"
}
I can extract the name by :
name = json.loads(request.body).get("name")
Now I have a GET request in which I am passing bearer token.
How should I extract it in Django?

You can access the authorization header with request.META['HTTP_AUTHORIZATION']

Related

How to implement third party authentication in gramex

I am trying to build a simple gramex application. where i need to authorize user from linkedin, outlook, Github & gmail.
Please share some code snippet.
url:
auth/github:
pattern: /$YAMLURL/github
handler: OAuth2
kwargs:
# Create app at https://code.gramener.com/admin/applications/
client_id: 'YOUR_APP_CLIENT_ID' # https://github.com/settings/connections/applications/
client_secret: 'YOUR_APP_SECRET_ID'
authorize:
url: 'https://github.com/login/oauth/authorize'
scope: [repo, gist, user]
access_token:
url: 'https://github.com/login/oauth/access_token'
body:
grant_type: 'authorization_code'
user_info:
url: 'https://api.github.com/user'
headers:
Authorization: 'Bearer {access_token}'
redirect:
query: next
header: Referer
url: .
This is the code snippet for Github with OAuth2
https://docs.github.com/en/developers/apps/building-oauth-apps
client_id: Create an app with the OAuth2 provider to get this ID
client_secret: Create an app with the OAuth2 provider to get this ID
authorize: Authorization endpoint configuration
url: Authorization endpoint URL
scope: an optional a list of scopes that determine what you can access
access_token: Access token endpoint configuration
url: Access token endpoint URL
user_info: Optional user information API endpoint
url: API endpoint to fetch URL
headers: optional dict containing HTTP headers to pass to user info URL. e.g.
Authorization: 'Bearer {access_token}'. Default: {User-Agent: Gramex/}

Flask-Login, Session Management and AJAX

I'm having trouble getting an AJAX call to work with the Flask-Login current_user object and the #login_required decorator. I believe it has something to do with the session not being passed.
The goal is for a user to click on a link that makes an AJAX call to a route URL that will provide a SSO session ID through a SOAP service. The SOAP service requires an emp_id to be passed which can be accessed through the current_user.emp_id attribute.
I initially attempted the AJAX call without the #login_required decorator and just passing a simple message as such which returned successfully:
app.js
const ssoLinks = document.querySelectorAll('.sso');
ssoLinks.forEach((ssoLink) => {
ssoLink.addEventListener('click', (e) => generateSSOLink(e, ssoLink.id));
});
function generateSSOLink(e, page) {
e.preventDefault();
fetch("/get_bpm_sso_link")
.then(response => response.json())
.then(data => console.log(data))
}
views.py
#app.route('/get_bpm_sso_link')
def get_bpm_sso_link():
data = {
'msg': 'success'
}
print('*'*75)
print('SUCCESS')
print('*'*75)
return jsonify(data)
My next attempt was to access the emp_id in current_user:
views.py
#app.route('/get_bpm_sso_link')
def get_bpm_sso_link():
data = {
'msg': 'success'
}
print('*'*75)
print(current_user.emp_id)
print('*'*75)
return jsonify(data)
Which gave me this error:
AttributeError: 'AnonymousUserMixin' object has no attribute 'emp_id'
Okay, so then I decided to try and access the same emp_id attribute on the initial index page(where the AJAX lives as well) and was able to do so. It sounds like during an AJAX request, the Flask-Login LoginManager doesn't recognize the session of the current_user. To further this claim, I added the #login_required decorator to the route and the JSON response returned a redirect to the login page.
What can I do to have Flask-Login recognize a user during an AJAX call? If not, what other libraries can handle user session management and AJAX requests seamlessly?
So I did some digging this week at Pycon 2018 in Cleveland and came across a noteworthy topic regarding the Fetch API. Seems by default that the API doesn't send any user credentials. To remedy this, it all came down to setting an option within the API:
app.js
function generateSSOLink(e, page) {
e.preventDefault();
fetch("/get_bpm_sso_link", {
credentials: 'include'
})
.then(response => response.json())
.then(data => console.log(data))
}
Now my AJAX request hits my view even with the #login_required decorator.
What you need is to login using request loader as per this example on flask for each request
And probably disable setting the Flask Session cookie
Then Using fetch add headers with basic authentication
fetch('/get_bpm_sso_link', {
method: 'get',
//or whichever method you are using
headers: new Headers({
'Authorization': 'Basic '+btoa('username:password')
//btoa base64 encodes your credentials, the flask example above shows how to decode
})
});
Ideally because the credentials are not hashed, they should be passed over https in production

Authenticate restframework User in python

So, i new in django and djangorestframework. i followed their tutorial in their page. http://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/
in that tutorial, you can login as django user from djangorestframework api login page. my question is, if i want to make a CLI or GUI application and using requests module to post a content to the API, but the API must be loggged in first. how i do that?
In DRF, you can add additional package for simple token-based Authentication. Add rest_framework.authtoken to INSTALLED_APPS. To make HTTP(S) request to client you pass the authorization token like this Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
For testing, you can use curl
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
Read more...
You can set that a user must be authenticated at all times as default setting in settings.py (in your web server project):
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
More info about that here.
In your web client project, like one of the comments on your questions mentions, you must add an Authentication header in the HTTP messages you send to the web server. An example (TypeScript Angular application implementation) would be:
import {Injectable} from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Spacecraft} from '../model/spacecraft';
/* Create the authentication headers for the HTTP requests to the DRF project's API.
* Note: uses btoa(): base-64 encoding of ASCII string, see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa.
*/
const basicAuthenticationToken = btoa(environment.REST_API.username + ':' + environment.REST_API.password);
const httpOptions = {
headers: new HttpHeaders({
'Authorization': `Basic ${basicAuthenticationToken}`
})
};
#Injectable()
export class APICommunicationService {
constructor(private http: HttpClient,
private notificationsService: NotificationsService) {
}
getSpacecraftInfo(url: string): Observable<Spacecraft> {
return this.http.get<Spacecraft>(url, httpOptions)
}
}

How do I pass a CSRF token using the python-requests library?

I have an app which needs to redirect to another url from outside with some POST data. I have the CSRF token value to the other app. How do I construct a simple POST request with requests library in Python??
csrf_token = "kjsbfckjsdnfcksdnkl"
post_data = {'email': email, 'answer': answer}
response = request.post(URL, data=post_data)
Where do I add the CSRF token?
You can either send the CSRF token as a POST parameter or a HTTP header.
Edit: a Referer HTTP header is also required by Django's CSRF protection. It needs to have the same origin as the request.
Using POST parameters:
post_data = {'email': email, 'answer': answer, 'csrftoken': csrf_token_value}
headers = {'Referer': URL}
response = request.post(URL, data=post_data, headers=headers)
Using HTTP headers:
post_data = {'email': email, 'answer': answer}
headers = {'X-CSRFToken': csrf_token_value, 'Referer': URL}
response = request.post(URL, data=post_data, headers=headers)
Another workaround is to use csrf_exempt decorator.
https://docs.djangoproject.com/en/3.2/ref/csrf/#django.views.decorators.csrf.csrf_exempt .
In case you are using a recent Django with CsrfMiddleware add it to the post_data dict:
post_data = {'email': email, 'answer': answer, 'csrfmiddlewaretoken': 'yourtoken'}
Check a form if the variable name is correct.
If you want to redirect on the same server, just call die other view function.
Take a look at the official documentation, which covers sending a POST request with a CSRF token.
CSRF tokens are stored in cookies (as far as I know). Since that's the case, you can store the cookie value as some variable, then use that value in your request.
I suggest you to use session objects of request library.
Moreover, if you’re making several requests to the same host, the underlying TCP connection will be reused, which can result in a significant performance increase and A Session object has all the methods of the main Requests API.

How to use TokenAuthentication for API in django-rest-framework

I have a django project, using django-rest-framework to create api.
Want to use token base authentication system so api call for (put, post, delete) will only execute for authorized user.
I installed 'rest_framework.authtoken' and created token for each users.
So, now from django.contrib.auth.backends authenticate, it returns user, with auth_token as attribute. (when loged in successfully).
Now my question is how can I send the token with post request to my api and
at api side how can I verify if token is valid and belongs to the correct user?
Are there any methods in app rest_framework.authtoken to validate given user and its token?
not found this very useful!
Update (changes I made):
Added this in my settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
)
}
Also sending Token in my header but its still not working:
if new_form.is_valid:
payload= {"createNewUser":
{ "users": request.POST["newusers"],
"email": request.POST["newemail"]
}
}
headers = {'content-type' : 'application/json',
'Authorization': 'Token 6b929e47f278068fe6ac8235cda09707a3aa7ba1'}
r = requests.post('http://localhost:8000/api/v1.0/user_list',
data=json.dumps(payload),
headers=headers, verify=False)
"how can I send the token with post request to my api"
From the docs...
For clients to authenticate, the token key should be included in the Authorization HTTP header. The key should be prefixed by the string literal "Token", with whitespace separating the two strings. For example:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
"at api side how can I verify if token is valid and belongs to the correct user?"
You don't need to do anything, just access request.user to return the authenticated user - REST framework will deal with returning a '401 Unauthorized' response to any incorrect authentication.
To answer the first half of your question:
how can I send the token with post request to my api
You can use the Python requests library. For the django-rest-framework TokenAuthentication, the token needs to be passed in the header and prefixed by the string Token (see here):
import requests
mytoken = "4652400bd6c3df8eaa360d26560ab59c81e0a164"
myurl = "http://localhost:8000/api/user_list"
# A get request (json example):
response = requests.get(myurl, headers={'Authorization': 'Token {}'.format(mytoken)})
data = response.json()
# A post request:
data = { < your post data >}
requests.post(myurl, data=data, headers={'Authorization': 'Token {}'.format(mytoken)})
I finally have the django "rest-auth" package working for token authentication.
If this helps, here is the client-side jQuery code that worked for me, after you successfully log in and receive the "auth_token":
var user_url = {API URL}/rest-auth/login
var auth_headers = {
Authorization: 'Token ' + auth_token
}
var user_ajax_obj = {
url : user_url,
dataType : 'json',
headers: auth_headers,
success : function(data) {
console.log('authorized user returned');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
console.log('error returned from ' + user_url);
}
};
$.ajax(
user_ajax_obj
);
If you are using coreapi. To add the Authorisation you do
import coreapi
auth = coreapi.auth.TokenAuthentication(scheme='Token', token=token_key)
Then you can do
client = coreapi.Client(auth=auth)
response = client.get(my_url)

Categories

Resources