Authenticate an API call correctly with requests and sessions - python

I want to call my own API in a custom view I wrote. Normally I use JWT authentication with my API calls. In this specific view though, I'd like to use a different authentication.
I want to enable logged in users to make a successful get call (without a token). Not logged in users should not be able to make that call. I tried this with Basic Authentication and Session Authentication but don't really get it tow work.
Here is my view that makes the API call:
def visualize_buildings(request, id):
passed_id = id
endpoint = 'linktomyendpoint' + str(passed_id)
response = requests.get(endpoint)
building_group_data = response.json()
# print(building_group_data)
if 'buildings' in building_group_data:
building_data = building_group_data['buildings']
context = {'building' : building_data}
return render(request, 'building_group_visualize_api.html', context)
else:
return HttpResponseNotFound("Ups. We are sorry but no Building Group was found with that id")
Here my API view:
class BuildingGroupRetrieveAPIView(RetrieveAPIView):
authentication_classes = [JSONWebTokenAuthentication,
SessionAuthentication, BasicAuthentication]
serializer_class = BuildingGroupSerializer
queryset = BuildingGroup.objects.all()
The view works with if I send a token in the headers. But how can I use Session Authentication with that? I tried getting username and password from the request and then pass it to the API call. But that doesn't work because I can't decode the password from the request (which makes sense).
So I tried to follow this: https://2.python-requests.org/en/master/user/advanced/ but I still can't authenticate my request.
Can anyone point me into the right direction? Help is very much appreciated! Thanks in advance!

Session ids are saved as a cookie on the user's device and they will be sent to the server as a header name Cookie. So if you want to use cookies instead of the JWT token then you should send your request with the session id as a cookie header.
This is the header that lets Django know your session-id when you visit the site directly:
Cookie: csrftoken=some-csrf-token; sessionid=your-session-id
Now to make your request contain something like that:
cookies = {'sessionid': 'your-session-id'}
response = requests.get(endpoint, cookies=cookies)
Note that Django might still through an error for csrf token based on your settings.
You can find your session-id on your browser. If you don't know where and how to access them, just google it. it's different based on the browser you use.

Related

How to authenticate users using GET request in FastAPI?

I am new to APIs and I need to be able to authenticate users using a GET request, in order to automate processes in airflow.
Is it possible to authenticate using GET request? For example:
hhtp://localhost:8000/transformar?user:password
In general, it is a very bad idea to do password authentication in a GET request. The obvious reason is that you have the username and password in the URL params (after ?).
The standard way of doing it is having a login API something like
POST http://localhost:8000/login and provide the username and password in form-data. When you authenticate the user, you can return a token. This can be an API Key of a JWT token, etc.
Now, using this token you want to send any following requests. So, in the next GET request, place this token in your header under "Authentication". Once you verify the token, you can return response data or, otherwise, raise a 403 Unauthorised error.
FastAPI provides proper documentation on how to implement this here.

Django session not available on two seperate requests

Description:
In the django session docs it says:
You can read it and write to request.session at any point in your view.
But I can't access the session when making a second request to the same view:
views.py
class Login(APIView):
def post(self, request):
print("before: ", request.session.get("user")
request.session["user"] = "admin"
print(request.session.get("user")) #outputs 'admin'
return Response()
Expected Output:
After the second request (made with jquery $.post) it should output:
"admin"
Output:
Instead it outputs:
None
How can I make sessions available between independend requests?
As mentioned by #AbdulAzizBarkat in the comments, the problem was that the session credentials were not sent to the backend. The way the sessions work in a cross-domain scenario is:
User is verified in backend
Session is sent to the frontend and stored in the browser
The session credentials have to get sent to the backend on every request
You cannot, however, read this session cookies, like mentioned here:
The browser cannot give access to 3rd party cookies like those received from ajax requests for security reasons, however it takes care of those automatically for you!
The provided solution using ajax and setting xhrFields: { withCredentials: true } did not work for me.
Answer:
Instead of an ajax request, I used fetch requests.
It is important to set credentials: "include" since otherwise cookies won't be sent cross-origin. A request looks like this:
fetch(`${API}/login`, {
credentials: "include",
method: "POST",
body: data,
}).then(...).catch(...);

Passing values from HTML to python using EVE rest framework

I am creating a website using html as a frontend and python as a backend using EVE framework. I have enabled token authentication for my usersRESTful Account Management. But when I pass the values to the EVE framework it gives me a 401.
var login = function (loginData) {
var deferred = $q.defer();
$http.post(appConfig.serviceUrl + 'user',{data:loginData})
here the loginData holds the username and password of my user from the html page this piece of code is inside a .js file.
My api.py holds the following authentication code.
class RolesAuth(TokenAuth):
def check_auth(self, token, allowed_roles, resource, method):
# use Eve's own db driver; no additional connections/resources are used
accounts = app.data.driver.db['user']
lookup = {'token': token}
if allowed_roles:
lookup['roles'] = {'$in': allowed_roles}
account = accounts.find_one(lookup)
return account
def add_token(documents):
# Don't use this in production:
# You should at least make sure that the token is unique.
for document in documents:
document["token"] = (''.join(random.choice(string.ascii_uppercase)
for x in range(10)))
My problem is as soon as the api.py is run it asks to provide proper credentials. How can i send the token directly to the auth mechanism so that it lets me access the db.
How will you suggest me to get rid of the authentication alert box.
I want the token to be automatically sent to the api.
If suppose I use basic authentication how can I send the username and password values directly and validate it? Without having the browser pop-up box asking for username and password
Thanks in advance.
Does it work with curl ? Refer to this question
Also, refer to this and this thread on the mailing list.

GAE/Python - redirect working from main class but not from called method

When I make a redirect from main.py, it works, but when I try to redirect from within a method that it calls, nothing happens. There is no error, the program simply does nothing.
main.py
from githubauth import GetAuthTokenHandler
class AuthUser(webapp2.RequestHandler):
"""
If no environment variable exists with the access token in it,
auth the user as an admin. If it does exist, auth them as a regular
user.
"""
def get(self):
if not ACCESS_TOKEN:
# No access token exists, auth user as admin
get_auth_token = GetAuthTokenHandler()
get_auth_token.get()
githubauth.py
import webapp2
class GetAuthTokenHandler(webapp2.RequestHandler):
"""Redirect users to github to get an access request token."""
def get(self):
self.redirect('http://api.github.com/authorize')
It depends on what kind of authorization you're doing with Github, there are two ways to do that, OAuth token authorization and Web Application Flow.
OAuth Token Authorization
If you're doing OAuth authorization, you don't have to create a request handler to fetch Github auth token, request handler is for serving specific url on your server, for this kind of task, you should use urlfetch().
So the whole flow should be like the following code:
import webapp2
from google.appengine.api import urlfetch
def getAuthToken():
github_auth_url = "http://api.github.com/authorizations"
result = urlfetch.fetch(github_auth_url)
return result
class AuthUser(webapp2.RequestHandler):
def get(self):
if not ACCESS_TOKEN:
# No access token exists, auth user as admin
get_auth_token = getAuthToken()
# do something with your token...
Redirect Authorization (Web Application Flow)
This is the case if you have applied a client id, and want to be authorized by users as a standalone web application, the steps of this kind authorization is more complicated than former one:
Redirect users to request GitHub access
GitHub redirects back to your site
If you don't know about this flow, take a look at Github OAuth - Web Application Flow
Let's see how could we do within Google App Engine
Redirect users to request Github access
This is the part which involved in your sample, simply redirect user to the authorize url with specified parameters
from urllib import urlencode
class AuthUser(webapp2.RequestHandler):
def get(self):
# ... do something ...
# Github configuration
github_client_id = "Your github client id..."
github_redirect_url = "Your url for github redirecting users back to your GAE"
github_scope = "Gtihub scopes...."
github_authorize_url = "http://github.com/login/oauth/authorize"
github_authorize_parameters = {
'client_id': github_client_id,
'redirect_url': github_redirect_url,
'scope': github_scop
}
if not ACCESS_TOKEN:
# if no access_token found on your site, redirect users to Github for authorization
url_to_redirect = "%s?%s" % (github_authorize_url, urlencode(github_authorize_parameters))
self.redirect(url_to_redirect)
Github redirects users back to your site
Github will redirect users back to your site based on the previous parameter redirect_url, so you will have to prepare another request handler for receiving redirection from Github.
(You can do this is the same request handler, but it will mess your code)
The redirection back from the step 1 will contains one parameter, code, you will need it to exchange for an access token.
from urllib import urlencode
class GithubRequestHandler(webapp2.RequestHandler):
def get(self):
# this handler need to be bind to redirect_url
# get authentication code
github_code = self.request.get('code')
# prepare data to exchange access token
github_token_url = "https://github.com/login/oauth/access_token"
github_token_parameters = {
'client_id': 'Your Github client id',
'client_secret': 'Your Github client secret',
'code': github_code}
# exchange access token
data = urlfetch.fetch(github_token_url, payload=urlencode(github_token_parameter), method='POST')
# data will perform in the following form:
# access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&scope=user%2Cgist&token_type=bearer
# extract access_token from the string
# save the access_token to user's model
P.S.
the code is kinda of simulation of your application flow, it needs some tuning to be able to run on production :)
You try to create a webapp2 request handler, but it cannot be done this way. get_auth_token is not a WSGI webapp2 handler instance.
If you do not change githubauth.py you have to change your main.py.
class AuthUser(webapp2.RequestHandler):
def get(self):
if not ACCESS_TOKEN:
self.redirect(to your GetAuthTokenHandler)
This will result in two redirects if you do not have an access token.
RequestHandler needs to be instantiated with a request and a response for things to work properly.
That said, instantiating one and calling methods on it from inside the handler-method of another is pretty weird.

How to clear cookies using Django

I am trying to develop login page for a web site. I am using Django 1.4.2. I stored users which logged on correctly to a cookie using set_cookie. But I didn't find clear_cookie in Django's documentation. How to clear a cookie to make a user log out?
Setting cookies :
def login(request):
response = HttpResponseRedirect('/url/to_your_home_page')
response.set_cookie('cookie_name1', 'cookie_name1_value')
response.set_cookie('cookie_name2', 'cookie_name2_value')
return response
Deleting cookies :
def logout(request):
response = HttpResponseRedirect('/url/to_your_login')
response.delete_cookie('cookie_name1')
response.delete_cookie('cookie_name2')
return response
You can simply delete whatever you've stored in the cookie - this way, even though the cookie is there, it no longer contain any information required for session tracking and the user needs to authorize again.
(Also, this seems like a duplicate of Django logout(redirect to home page) .. Delete cookie?)

Categories