I am new to Stack overflow. I developed an API using Flask but I want to add security to it so that only those who has some key can run it. No database at backend, any token based or other latest secure way of running the API?
For eg: app.route('/test') if I run it using local_host/test then it triggered, the same way no one from the team who has the same access should not run that easily until and unless I(Producer) provide some key to Consumer and Consumer uses that key to connect my API.
The best way to do this is with basic authentication. This means that every time someone makes a request to your endpoint, they need to supply a username and password in the header with the request.
A great minimal example is located here: https://flask-httpauth.readthedocs.io/en/latest/
from flask_httpauth import HTTPBasicAuth
app = Flask(__name__)
auth = HTTPBasicAuth()
#auth.verify_password
def verify_password(username, password):
if username == 'approved_username' and password == 'correct-password':
return True
return False
#app.route('/')
#auth.login_required
def index():
return "Hello, %s!" % auth.username()
if __name__ == '__main__':
app.run()
I've modified it slightly to make it even more simple by removing the dynamic user lookup.
To use this, you just need to add the auth.login_required decorator to any route you wish to protect.
Related
I currently have a single-tenant eve app which works great, but would like to make it multi-tenant. That is, I want to allow multiple users to login where each gets a totally separate database (or different tables?).
I looked at flask-login for managing the user login (and registration) piece, but I am unclear on how to integrate this into my existing eve app so that each user has a different database.
The eve documentation at http://python-eve.org/authentication.html#auth-driven-database-access has the sample below.
from eve.auth import BasicAuth
class MyBasicAuth(BasicAuth):
def check_auth(self, username, password, allowed_roles, resource, method):
if username == 'user1':
self.set_mongo_prefix('MONGO1')
elif username == 'user2':
self.set_mongo_prefix('MONGO2')
else:
# serve all other users from the default db.
self.set_mongo_prefix(None)
return username is not None and password == 'secret'
app = Eve(auth=MyBasicAuth)
app.run()
However, this assumes that MONGO1 and MONGO2 are statically defined in my settings.py. Is there a way to dynamically create a new database for each user which is registered with my app?
Thanks in advance,
Keith
I have written a simple Python Flask API which does operations like adding data to Database and getting data from Database, there is no UI for this API, Now I want to implement OAuth authentication system for this simple API, As there is NO GUI, I cant use google or FB Oauth Providers which redirects users to there login page.
In simple words, i want to create my own GUI less oauth Authentication system which secures my API as any user who wants to access my API should pass through this authentication system by passing access token in a header
I need Oauth Authentication system of my own for the API's below:
from flask import Flask, redirect, url_for, session
from flask import Flask,jsonify,request,make_response
from flask_login import login_user,logout_user,current_user,login_required,LoginManager,login_manager
from flask_oauth import OAuth
import json
from flask_mysqldb import MySQL
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_oauthlib.provider import OAuth1Provider
app = Flask(__name__)
class MYWIFI(db.Model):
__tablename__ = 'MYWIFI'
id = db.Column('id', db.Integer, primary_key=True)
data = db.Column('data', db.Unicode)
def __init__(self, id, data):
self.id = id
self.data = data
#app.route('/getall')
def getall():
access_token = get_access_token()
if access_token is None:
return redirect(url_for('login'))
else:
languages = [u.__dict__ for u in db.session.query(MYWIFI).all()]
for d in languages:
del d['_sa_instance_state']
print(languages)
languagesJSON = json.dumps(languages)
return languagesJSON
#app.route('/insert', methods=['GET','POST'])
def insert():
access_token = get_access_token()
if access_token is None:
return redirect(url_for('login'))
else:
if request.method == 'POST':
insert = request.get_json()
id = insert['id']
data = insert['data']
print id
print data
new = MYWIFI(id, data)
db.session.add(new)
db.session.commit()
return "Success"
def main():
app.run()
if __name__ == '__main__':
main()
Please can anyone help me in kick starting this
I appreciate for this help
If I understood correctly, what you want is to build API endpoints which are protected by OAuth 2.0 tokens. If that's the case you as the API builder does not have to worry how token obtaining process happens. The client that consumes your APIs must perform the token obtaining and pass them to your end.
About sending in headers, try to stick with standards already exist in the OAuth 2 domain. RFC6750 defines how to use tokens once a client obtains them. It defines bearer authentication schema to transmit access tokens. Check section 2.1 to how header is set.
GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM
Where mF_9.B5f-4.1JqM is the access token. Once your API receives a request, from your end you must validate the access token before granting access. For this there is RFC7662 which define the methodology to validate access token against the authorization server. See section 2 Introspection endpoint to get an understanding of it. Alternatively, access token can come in a JWT format thus allowing it to be self contained.
Unfortunately, I do not have code for proposed solutions. They will considerable amount of codes. But I suggest you to separate authorization logic from your code. That means validation of authorization must be a separate module in your python code. But below I give a suggestion with my python knowledge.
#app.route('/insert', methods=['GET','POST'])
def insert():
access_token = get_access_token()
# Auth Validation for insert - This is based on access tokens
# If token is invalid/not-present, exception is thrown with HTTP 401 - unauthorized
my_auth_module.validate_access_token(access_token)
if request.method == 'POST':
insert = request.get_json()
id = insert['id']
Also one final thing, your API should not worry about redirection for login. Let it be handled by your API client upon the 401 - Unathorized response.
I got a flask application with different apps inside, using BluePrint.
To simplify, I got an API that manages token web authentification (and a lot of other data functions) and a website that should call the API to get the valid token, using a basic auth to start with
The issue is that when the website requests the API, it never gets any feedback from the API.
Requesting the API via POSTMAN works like a charm, but this call below, done from a website route is waiting, waiting, waiting and never ends.
So my assumption is that using the same port for both website and api is the issue
I could of course divides the flask into 2 flask apps with 2 servers, but there are many objects and tools both API and website are sharing, so I dont want to double the job
Thanks.
call from the website
from requests.auth import HTTPBasicAuth
import requests
mod = Blueprint('site', __name__, template_folder='templates/login')
def load_user(username, password):
data = requests.get('http://127.0.0.1:5000/api/login',
auth=HTTPBasicAuth('username', 'password'))
return data
#mod.route('/')
def index():
username = 'jeje'
password = 'jeje'
data = load_user(username, password)
return '<h1>load user<h1>'
the api function
#mod.route('/login')
def login():
resu = True
auth = request.authorization
if not auth or not auth.username or not auth.password:
resu = False
user = USER.query.filter_by(username = auth.username).first()
if not user:
resu = False
if validehash(user.password, auth.password):
period_in_mn = 120
payload = {
'public_id':user.public_id,
'exp' : datetime.datetime.utcnow() + datetime.timedelta(minutes = period_in_mn)
}
token = createtoken(payload, current_app.config['SECRET_KEY'])
if resu:
return jsonify({'token' : token })
else:
return jsonify({'token' : 'unknown'})
I guess your using flask 0.12 instead of 1.0. So whats happening here is that you're requesting a route from within another route.
Your browser requests /, and in your index function, you request /login. But the flask process is still working on the / request from the browser, and can't take any other requests, because flask 0.12 is working on a single core only.
Requesting like this is bad design. You could make a helper function, which returns the same data in different requests (either api or main site), or you could make the browser send another request using AJAX.
Flask 1.0 has multicore support, so I think this might work over there, but I really think you should change your design. This has absolutely nothing to do with blueprints by the way.
from flask import Flask, redirect
import requests
app = Flask(__name__)
#app.route('/')
def index():
result = requests.get('http://127.0.0.1:5000/api/login')
return 'this is the index<br>' + result.text
#app.route('/api/login')
def login():
return 'you are logged in'
Using flask 0.12, times out when visiting http://127.0.0.1:5000/.
Using flask 1.0, returns this is the index
you are logged in when visiting http://127.0.0.1:5000/.
I made an endpoint called /cars.
A person can create cars with a frontend, but devices read cars using an SDK, which has an API Key. This way, 2 rent-a-car companies can use the API without getting the cars mixed-up. Each app has its own API Key and its own person managing the contents.
This is being implemented with django restframework 3.x and django-oauth-toolkit.
I'm writing a test for a human retrieving cars, and another for a device.
This is failing:
def test_get_list(self):
# devices have a django user (AUTH_USER_MODEL ---onetoone--- Device)
self.client.force_authenticate(user=self.user_device)
self._get_list()
self.client.force_authenticate(user=None)
force_authentication sets request.auth to None. However, with postman or httpie, request.auth contains the Application object.
The queryset is:
def get_queryset(self):
if hasattr(self.request.user, 'device'):
# get the cars created by the owner of the API Key
return self.request.auth.application.user.cars.all()
return self.request.user.cars.all() # get my cars
Does this approach in the queryset make sense?
Am I testing it in the wrong way?
Why is request.auth empty? Is force_authentication using BasicAuthentication?
I would recommend going with check_object_permission for this kind of checks. You can read more here.
DRF documentation states that you need to force_authenticate the request if you are using APIRequestFactory. From the documentation:
from rest_framework.test import force_authenticate
factory = APIRequestFactory()
user = User.objects.get(username='olivia')
view = AccountDetail.as_view()
# Make an authenticated request to the view...
request = factory.get('/accounts/django-superstars/')
force_authenticate(request, user=user)
response = view(request)
To authenticate with APIClient try using credentials. Example from the documentation:
from rest_framework.authtoken.models import Token
from rest_framework.test import APIClient
# Include an appropriate `Authorization:` header on all requests.
token = Token.objects.get(user__username='lauren')
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='Token ' + token.key)
The same is the second question.
As pointed in the documentation force_authenticate bypass authentication therefore it's your job to simulate the missing authentication part, including filling the request.auth.
Otherwise, you'll need to configure a data set and call either login or credential on the APIClient instance.
I have a django server app that communicates with a gwt front-end using JSON. I want to introduce user authentication to the app and have started to incorporate the framework provided by django. At this point I have set up the server to respond with the user authentication form when necessary (using the #login_required decorator scheme described in the above link), but I'm not sure what to do with this in GWT.
If you are using GWT with django and have implemented user auth, it would be great to hear how you set things up.
Thanks.
The autotest project used gwt and django combination. Have a look at http://autotest.kernel.org/browser/trunk/frontend source code. To be specific I would modify http://autotest.kernel.org/browser/trunk/frontend/afe/json_rpc/serviceHandler.py and add something like below (which would filter login, logout and is__logged__in and for all other functions it would invoke request.user.is_authenticated() to make sure that all other json rpc are protected)
def invokeServiceEndpoint(self, meth, request, response, args):
if meth.func_name == "login" or meth.func_name == "logout" or meth.func_name == "is_loggedin":
return meth(request, *args)
else:
if request.user.is_authenticated():
return meth(request.user, *args)
else:
from studio.rpc_exceptions import AccessDeniedException
raise AccessDeniedException()
I never used Django, but you probably can set what will be returned when login is required.
You can, for instance, return a message so the client can prompt the user with the authentication form. Of course, you would need to account for this situation in every call, but then you could create a abstract request class to do this.