I'm working my way through Miguel Grinberg's book Flask Web Development, and I've run into a snag in Chapter 14 (Application Programming Interfaces) with the authentication routine. I'm attempting to update the code to use the current version of flask-HTTPAuth according to the example code in the github repo. I can authenticate to HTTPBasicAuth with email/password, but when I try to pass a token I still get a password prompt.
Here is my app/api/authentication.py file:
from flask import g, jsonify
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth, MultiAuth
from ..models import User
from . import api
from .errors import forbidden, unauthorized
basic_auth = HTTPBasicAuth()
token_auth = HTTPTokenAuth(scheme='Bearer')
multi_auth = MultiAuth(basic_auth, token_auth)
#basic_auth.verify_password
def verify_password(email, password):
if email == '':
return False
user = User.query.filter_by(email=email).first()
if not user:
return False
g.current_user = user
g.token_used = False
if user.verify_password(password):
return user
else:
return False
#token_auth.verify_token
def verify_token(token):
user = User.verify_auth_token(token)
if user:
g.current_user = user
g.token_used = True
return user
else:
return False
#basic_auth.error_handler
def auth_error():
return unauthorized('Invalid credentials')
#token_auth.error_handler
def auth_error():
return unauthorized('Invalid credentials')
#api.before_request
#multi_auth.login_required
def before_request():
if not g.current_user.is_anonymous and not g.current_user.confirmed:
return forbidden('Unconfirmed account')
#api.route('/tokens/', methods=['POST'])
#multi_auth.login_required
def get_token():
if g.current_user.is_anonymous or g.token_used:
return unauthorized('Invalid credentials')
return jsonify({'token': g.current_user.generate_auth_token(), 'expiration': 3600})
I'm using Python 3.10.6, Flask 2.2.2 and HTTPie 3.2.1. What am I doing wrong?
I've figured it out. The current version of HTTPie (3.2.1) needs to know whether you're sending a token or a userid:password pair. To do this, you use the command
http --auth <username>:<password> ...
for basic authentication or
http --auth-type bearer --auth <token> ...
for token authentication.
Related
I am trying to using to use Flask-JWT extended at the basic level at the moment.
I get the user and password authenticated from the user form. I create an accesss token, include it in the response and route to another protected route. Please find the shorter version of code as below...
from flask import Flask, jsonify, request
from flask_jwt_extended import,JWTManager, jwt_required, create_access_token,get_jwt_identity)
app.config['JWT_SECRET_KEY'] = 'super-secret'
jwt = JWTManager(app)
app.config['JWT_TOKEN_LOCATION'] = ['headers']
app.config['JWT_BLACKLIST_ENABLED'] = True
jwt = JWTManager(app)
app.config['PROPAGATE_EXCEPTIONS'] = True
#log_blueprint.route('/', methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == 'POST':
if error is None and username = form.request['user'] and pwd = form.request['pwd'] :
access_token = create_access_token(identity=user)
resp = redirect(url_for('log_blueprint.protected'),access_token)
resp.headers = {'Authorization': 'Bearer {}'.format(access_token)}
return resp
#log_blueprint.route('/protected', methods=["POST","GET"])
#jwt_required
def protected():
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
It gives me the error as below...
{"msg":"Missing Authorization Header"}
I tried the answers on this page...https://stackoverflow.com/questions/52087743/flask-restful-noauthorizationerror-missing-authorization-header
But couldnt get better.
Please let me know any solution for this issue.
Sorry if any typo mistake.
Thanks and regards,
Abhinay J K
Depending on the version you are using, accordind to change log of latest stable version, you should be using notation like:
#log_blueprint.route('/protected', methods=["POST","GET"])
#jwt_required()
def protected():
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
If you are using postman to send request, make sure you check the "key".
To set some context I'm creating an API through Flask. To authenticate users, I'm using
flask-HTTPAuth. As a part of accessing login protected resources, I've defined my verify_password callback in auth.py. If the user credentials provided evaluate to True, the user is attached to the g object.
In app.py, there is the route /api/v1/users/token, that when requested, a token is issued to a user that is logged in. However when I try to access g.user in app.py, I get the error: AttributeError: '_AppCtxGlobals' object has no attribute 'user'.
Why isn't there any existing 'user' attribute not while accessing the g object in app.py?
auth.py
from flask import g
from flask_http import HTTPBasicAuth
from models import User
basic_auth = HTTPBasicAuth()
#basic_auth.verify_password
def verify_password(username, password):
try:
api_user = User.get(User.username == username)
except User.DoesNotExist:
return False
user_verified = api_user.check_password(password)
if user_verified:
g.user = api_user
return True
return False
app.py
from flask import Flask, g, jsonify
from auth import basic_auth as auth
app = Flask(__name__)
#auth.login_required
#app.route("/api/v1/users/token")
def issue_api_token():
token = g.user.request_token()
return jsonify({'token': token})
The order of your decorators is wrong, #app.route should always be first.
#app.route("/api/v1/users/token")
#auth.login_required
def issue_api_token():
# ...
How can i perform basic authentication in bottle framework? in flask i used to:
def check( username, password ):
# This function is called to check if a username/password combination is valid
return username == 'nikos' and password == '******'
def authenticate():
# Sends a 401 response that enables basic auth
return Response( 'Credentials of a registered user required!', 401, {'WWW-Authenticate': 'Basic realm="User!"'} )
and called as:
auth = request.authorization
if not auth or not counters.check( auth.username, auth.password ):
return counters.authenticate()
How can i achieve the same in Bottle framework?
As reported here, Bottle natively contains a decorator that makes Basic Auth pretty straightforward:
from bottle import auth_basic, request, route
def is_authenticated_user(user, password):
# You write this function. It must return
# True if user/password is authenticated, or False to deny access.
#route('/')
#auth_basic(is_authenticated_user)
def home():
return ['hooray, you are authenticated! your info is: {}'.format(request.auth)]
Adapted from ron rothman with a basic auth solution using werkzeug.
from bottle import auth_basic, request, route
from werkzeug.security import generate_password_hash, check_password_hash
users = {'user1': generate_password_hash('pwd!')}
def is_authenticated_user(user, password):
# You write this function. It must return
# True if user/password is authenticated, or False to deny access.
return user in users and check_password_hash(users[user], password)
#route('/')
#auth_basic(is_authenticated_user)
def home():
return ['hooray, you are authenticated! your info is: {}'.format(request.auth)]
I am new to Flask and have been working on an existing app for its login module. It has to be delivered asap. The login credentials validates by Active Directory authentication, which is working as expected. I am referring this flask link which says
url_for('main', page=2): return the internal URL /?page=2. All optional keyword arguments are treated as GET parameters.
My index page is loaded from here (working perfectly):
#app.route("/", methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
userName = request.form['username']
pwd = request.form['password']
try:
ldapobject = auth.bind(userName,pwd)
return redirect(url_for('scheduler')) ----> NEED TO PASS USER AND PWD TO scheduler function using post here
except ldap.LDAPError, error_message:
error = 'Invalid Credentials. Please try again'
return render_template('login.html', error=error)
My scheduler function:
#app.route("/home", methods=['POST'])
def scheduler():
# some code here
# WANT TO HAVE USER CREDENTIALS IN THIS FUNCTION FROM login page
return render_template("scheduler.html", scheduler=form)
Problem: How to pass user's credentials to scheduler method as a POST call
If you want to persist user data between your application pages - you will need to store some session data on user side, e.g. cookies.
flask-login module (https://flask-login.readthedocs.org/en/) can do all the dirty work for you.
In short you need to create User class with several required fields and methods (https://flask-login.readthedocs.org/en/latest/#your-user-class) and specify several methods with decorators to load and check users that are being authenticated:
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app=app)
#login_manager.user_loader
def load_user(username):
return User(username)
#login_manager.request_loader
def load_from_request(request):
return User.auth_is_valid(request.authorization)
After that you can mark any routes that need user credentials with #login_requied decorator and access logged in user via current_user variable:
from flask_login import login_required, current_user
#app.route("/user_needed")
#login_required
def some_function():
print(current_user)
I'm trying to have my backend server sign and send the username at the end of an OAuth request. The example I'm trying to follow uses this package (https://www.npmjs.com/package/express-jwt) but my backend is in Google App Engine. So, I was wondering how I can achieve the same (signing the username with some secret) inside the App Engine/webapp2 framework?
First download python jwt to folder lib of projects
Code:
import cgi
import datetime
import webapp2
from base_handler import BaseRequestHandler, login_required
from webapp2 import Route
from models import Customer
from lib import jwt
import logging
def login_required(fn):
def check(self, *args, **kargs):
auth = self.request.headers.get('Authorization')
login_info = jwt.decode(auth, 'secret', algorithms=['HS256'])
# your verify login token here
logging.error(login_info)
# verify success
fn(self, *args, **kargs)
return check
class LoginHandler(BaseRequestHandler):
def login(self):
username = self.request.get('username')
password = self.request.get('password')
if Customer.login(username, password) is True:
encoded = jwt.encode({'username': username}, 'secret', algorithm='HS256')
self.response.write({'token': encoded})
return
self.response.write('login unsuccess', status=404)
class APIHandler(BaseRequestHandler):
#login_required
def get(self):
self.response.write('product found')
app = webapp2.WSGIApplication([
Route('/login', handler=LoginHandler, handler_method='login', name='login', methods=['POST']),
('/', APIHandler)
], debug=True)
Note: for test client you can usage postman and add header (token are get from login request)