How to put auth functionality in #app.before_request in flask - python

I want to make auth layer in flask app . I was using flask-jwt-extended for jwt auth so for that i have to mentioned #jwt_requied decorator for each protected route . so i dont want to do that for each protected route. I thought to define a function and make that to execute before each request by using #app.before_request. i want auth to happen in this layer.
def check_user_token():
if 'x-access-token' in request.headers:
token = request.headers['x-access-token']
if not token:
return jsonify({'message': 'Token is missing'}), 401
try:
data = jwt.decode(token, app.config['SECRET_KEY'])
current_user = UserDetails.query.filter_by(username=data['username']).first()
except:
return jsonify({'message': 'Token is in-valid'}), 401
return current_user
So this the function i want to call before each request to check auth.
#app.before_request
def before_calback():
#want to call that check_user_token() from here and
#also dont want to call that for 'login' route .
#Once i will get some response from check_user_token()
#based on that want to proceed further
#and here i dont know to do this.
Basically my qns is how to do authentication in #app.before_request def before_calback() ?

Can you access check_user_token()?
It would be like this
#app.before_request
def before_calback():
check_user_token()
If you can post the some code, it would be easier to help you.

Related

Flask jwt POST data to endpoint with a token

This Flask endpoint is what I am trying hit with Insomnia with a jwt token on a POST:
#app.route('/', methods=['POST'])
#token_required
def json_payloader():
try:
some code to do stuff...
Poking around the internet no matter what I try I always get back a:
{
"message": "Token is missing!"
}
Bearer authentication token:
OR with authentication set to None and just trying headers with the token this also fails:
Any tips try greatly appreciated.
EDIT token_required function
from flask import Flask, request, jsonify
import flask
from flask.helpers import make_response
import jwt
from functools import wraps
def token_required(f):
#wraps(f)
def decorated(*args, **kwargs):
token = request.args.get('token')
if not token:
return jsonify({'message': 'Token is missing!'}), 403
try:
data = jwt.decode(token, app.config['SECRET_KEY'])
except:
return jsonify({'message': 'Token is invalid'}), 403
return f(*args, **kwargs)
return decorated
Unless you're using a different version of flask-jwt (or flask-jwt-extended) then I believe the correct function decorator is #jwt_required()
Seems like you're using JWTs. So, the correct decorator to be used is #jwt_required.
Please see the example from https://flask-jwt-extended.readthedocs.io/en/stable/basic_usage/#basic-usage .
#app.route("/protected", methods=["GET"])
#jwt_required()
def protected():
# Access the identity of the current user with get_jwt_identity
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
If you want to create your own implementation, you can retrieve it like
auth_header = request.headers.get("Bearer", "").strip().strip(",")

Using JWT between two Flask applications

I have two separate Flask applications, one is an API with the domain "admin.company.com" and the second one is a dashboard under the domain "dashboard.company.com".
My main goal is to secure the api and enable authentication.
I set up authentication on the api and when I'm testing it via the swagger-ui it works good with no issues. I manage to authenticate myself and submit requests. On top of that, in the token_required() below I coded a section that expects to receive JWT and decode it:
def token_required(f):
#wraps(f)
def decorator(*args, **kwargs):
token = None
if 'jwt-token' in request.headers:
token = request.headers['jwt-token']
if not token:
return jsonify({'message': 'a valid token is missing'})
try:
current_user = False
# for authentication via the swagger-ui
if token == 'my_awesome_password':
current_user = 'admin'
else:
data = jwt.decode(token, app.secret_key)
current_user = 'admin' if data['public_id'] == 'admin' else False
if not current_user:
return jsonify({'message': 'token is invalid'})
except:
return jsonify({'message': 'token is invalid'})
return f(*args, **kwargs)
return decorator
The problem is with the dashboard application:
On the dashboard app, I configured the /login route to generate JWT (which needs to be sent to the api app in every HTTP request I made), then do a set_cookie() with httpOnly=True flag (for security purposes), but then how can the JavaScript access it when it has to make XHR requests? Having the httpOnly flag on makes it unreachable.
If using httpOnly=True is not the ideal way in this case, how can I tackle it and make sure the JWT will always be sent to the api app in the request headers?
I'm using PyJWT package.
Thanks for any help.
If you use JWTs for XHR requests, then you don't necessarily need to use cookies – the browser/consumer could store the token and attach it to every request. If you do want to use cookies (this is also a viable option) then you don't need to worry about attaching the JWT as the browser will do that automatically for the domains you specified in the set_cookie command.

Continue request flow after new access token is issued using refresh token

I am not able to figure out how do I continue the request flow after refreshing the expired JWT token in my Flask application.
I am storing access token and refresh token in their respective cookies.
This is how my flow looks like right now:
Below is my decorator function that checks validity of the JWT token
def check_valid_jwt(f):
#wraps(f)
def wrapper():
print(request.cookies)
if 'access_token_cookie' in request.cookies:
print('Verify Signature')
# some code that verifies the JWT signature
print('Signature verification successful')
# some code that extracts claims from the token
if time.time() > claims['exp']:
print('Token is expired')
# some code that get the new access token using refresh token
# What am I supposed to do here after I get the refresh token and continue the request while adding the new token to access_token cookie?
return f()
return wrapper
Here is how my protected endpoint looks like:
#check_valid_jwt
def secretpage():
return render_template("/home/secret_page.html")
After I get the refresh token, I want to continue the flow of the request and add new access token in the cookie but if I add that in check_valid_jwt decorator function, secretpage handler will have no idea that a new access token has been issued.
How do I do it in such a way that if a new access token has been issued, it gets added to the response. Am I complete off here and this is not how Authentication flow works?
The best way is to create a middleware for JWT authentication instead of a decorator
from flask import Flask
class JWTAuthMiddleware(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
access_token = environ.get('HTTP_AUTHORIZATION', None)
# validate access token here and get new one if required by using refresh token
# you can also update the invalid token in the header here if you want
environ['HTTP_AUTHORIZATION'] = 'new access token'
return self.app(environ, start_response)
Now wrap the actual wsgi app with this one
app = Flask(__name__)
app.wsgi_app = JWTAuthMiddleware(app.wsgi_app)

Is it possible to use Flask-Login's authentication as simple HTTP auth for a REST API?

Right now, my webapp has a full auth system implemented through Flask-Login. But say that I have this controller:
#app.route("/search_query")
#login_required
def search_query():
query = request.args.get("query")
return jsonify(search(query))
This works great when you login to the page and make searches against it, if you're authenticated it goes through, otherwise it routes you back to the login page (through an unauthorized_handler function).
#lm.unauthorized_handler
def unauthorized():
return redirect(url_for("login"))
The problem is, I want to be able to use some form of simple HTTP authentication for this without having two separate auth systems so that I can make REST API calls against it. In short, I want to avoid having to use both Flask-Login and HTTPBasicAuth, and just use Flask-Login to achieve simple authentication, is this possible through Flask-Login?
Use the flask-login's request_loader to load from request auth header. You don't need to implement the decorator yourself, and current_user will point to the user loaded.
Example:
login_manager = LoginManager()
#login_manager.request_loader
def load_user_from_header():
auth = request.authorization
if not auth:
return None
user = User.verify_auth(auth.username, auth.password):
if not user:
abort(401)
return user
With that, you can mark a view as login required by:
#app.route('/user/info')
#login_required
def user_info():
return render_template('user_info.html', current_user.name)
If you looking for users to authenticate and make REST API calls they are going to have to send their credentials with every api call.
What you could do is a new decorator that checks for the auth header and authenticate the user.
Please refer to the entire app that I've posted on codeshare for more info:
http://codeshare.io/bByyF
Example using basic auth:
def load_user_from_request(f):
#wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if current_user.is_authenticated:
# allow user through
return f(*args, **kwargs)
if auth and check_auth(auth.username, auth.password):
return f(*args, **kwargs)
else:
return bad_auth()
return decorated
With that code you can now decorate your views to check for the header.
#app.route("/search_query")
#load_user_from_request
def search_query():
query = request.args.get("query")
return jsonify(search(query))
you can curl my example app like this:
curl --user admin#admin.com:secret http://0.0.0.05000/success

How do you implement token authentication in Flask?

I'm trying to allow users to login to my Flask app using their accounts from a separate web service. I can contact the api of this web service and receive a security token. How do I use this token to authenticate users so that they have access to restricted views?
I don't need to save users into my own database. I only want to authenticate them for a session. I believe this can be done using Flask-Security and the #auth_token_required decorator but the documentation is not very detailed and I'm not sure how to implement this.
EDIT:
Here's a code example:
#main.route("/login", methods=["GET", "POST"])
def login():
payload = {"User": "john", "Password": "password123"}
url = "http://webserviceexample/api/login"
headers = {'content-type': 'application/json'})
#login to web service
r = requests.post(url, headers=headers, json=payload)
response = r.json()
if (r.status_code is 200):
token = response['user']['authentication_token']
# allow user into protected view
return render_template("login.html", form=form)
#main.route('/protected')
#auth_token_required
def protected():
return render_template('protected.html')
Hey there Amedrikaner!
It looks like your use-case is simple enough that we can implement this ourselves. In the code below, I'll be storing your token in the users session and checking in a new wrapper. Let's get started by making our own wrapper, I usually just put these in a wrappers.py file but can you can place it where you like.
def require_api_token(func):
#wraps(func)
def check_token(*args, **kwargs):
# Check to see if it's in their session
if 'api_session_token' not in session:
# If it isn't return our access denied message (you can also return a redirect or render_template)
return Response("Access denied")
# Otherwise just send them where they wanted to go
return func(*args, **kwargs)
return check_token
Cool!
Now we've got our wrapper implemented we can just save their token to the session. Super simple. Let's modify your function...
#main.route("/login", methods=["GET", "POST"])
def login():
payload = {"User": "john", "Password": "password123"}
url = "http://webserviceexample/api/login"
headers = {'content-type': 'application/json'})
#login to web service
r = requests.post(url, headers=headers, json=payload)
response = r.json()
if (r.status_code is 200):
token = response['user']['authentication_token']
# Move the import to the top of your file!
from flask import session
# Put it in the session
session['api_session_token'] = token
# allow user into protected view
return render_template("login.html", form=form)
Now you can check the protected views using the #require_api_token wrapper, like this...
#main.route('/super_secret')
#require_api_token
def super_secret():
return "Sssshhh, this is a secret"
EDIT
Woah! I forgot to mention you need to set your SECRET_KEY in your apps config.
Just a config.py file with SECRET_KEY="SOME_RANDOM_STRING" will do. Then load it with...
main.config.from_object(config)

Categories

Resources