Bad Request CSRF_token key error when using Angular and Flask - python

I am working on a simple user authentication feature for a website using Angular front end and Flask back end. Currently, API requests made through Postman are successful, but when trying to log in through the browser, I receive the console error that login:1 Access to XMLHttpRequest at 'http://localhost:5000/api/auth/login' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I am able to see that the inject_csrf_token() works in generating a csrf token, but when I print the response, the response.cookies['csrf_token'] returns blank. I have tried adding response headers for Access-Control-Allow-Origin with *, but am still receiving the KeyError: 'csrf_token' error.
Any assistance would be greatly appreciated, this has been a major blocker for a few days now.
Here are what I believe are the relevant files:
app.init.py
from flask import Flask, render_template, request, session, redirect
from flask_cors import CORS
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect, generate_csrf
from flask_login import LoginManager
from .models import db, User
from .api.user_routes import user_routes
from .api.auth_routes import auth_routes
from .seeds import seed_commands
from .config import Config
app = Flask(__name__)
# Setup login manager
login = LoginManager(app)
login.login_view = 'auth.unauthorized'
# Tell flask about our seed commands
app.cli.add_command(seed_commands)
app.config.from_object(Config)
app.register_blueprint(user_routes, url_prefix='/api/users')
app.register_blueprint(auth_routes, url_prefix='/api/auth')
db.init_app(app)
Migrate(app, db)
# Application Security
CORS(app)
#app.before_request
def https_redirect():
if os.environ.get('FLASK_ENV') == 'production':
if request.headers.get('X-Forwarded-Proto') == 'http':
url = request.url.replace('http://', 'https://', 1)
code = 301
return redirect(url, code=code)
#app.after_request
def inject_csrf_token(response):
print("INJECT: ", generate_csrf())
response.set_cookie(
'csrf_token',
generate_csrf(),
secure=True if os.environ.get('FLASK_ENV') == 'production' else False,
samesite='Strict' if os.environ.get(
'FLASK_ENV') == 'production' else None,
httponly=True)
response.headers.add("Access-Control-Allow-Origin", "*")
return response
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def react_root(path):
if path == 'favicon.ico':
return app.send_static_file('favicon.ico')
return app.send_static_file('index.html')
auth_routes.py
from flask import Blueprint, jsonify, session, request
from app.models import User, db
from app.forms import LoginForm
from app.forms import SignUpForm
from flask_login import current_user, login_user, logout_user, login_required
auth_routes = Blueprint('auth', __name__)
def validation_errors_to_error_messages(validation_errors):
"""
Simple function that turns the WTForms validation errors into a simple list
"""
errorMessages = []
for field in validation_errors:
for error in validation_errors[field]:
errorMessages.append(f'{field} : {error}')
return errorMessages
#auth_routes.route('/')
def authenticate():
"""
Authenticates a user.
"""
if current_user.is_authenticated:
return current_user.to_dict()
return {'errors': ['Unauthorized']}
#auth_routes.route('/login', methods=['POST'])
def login():
"""
Logs a user in
"""
form = LoginForm()
# Get the csrf_token from the request cookie and put it into the
# form manually to validate_on_submit can be used
print("##########REQUEST: ", request.cookies.to_dict())
form['csrf_token'].data = request.cookies['csrf_token']
if form.validate_on_submit():
# Add the user to the session, we are logged in!
user = User.query.filter(User.email == form.data['email']).first()
login_user(user)
return user.to_dict()
return {'errors': validation_errors_to_error_messages(form.errors)}, 401
#auth_routes.route('/logout')
def logout():
"""
Logs a user out
"""
logout_user()
return {'message': 'User logged out'}
#auth_routes.route('/signup', methods=['POST'])
def sign_up():
"""
Creates a new user and logs them in
"""
form = SignUpForm()
form['csrf_token'].data = request.cookies['csrf_token']
if form.validate_on_submit():
user = User(
username=form.data['username'],
email=form.data['email'],
password=form.data['password']
)
db.session.add(user)
db.session.commit()
login_user(user)
return user.to_dict()
return {'errors': validation_errors_to_error_messages(form.errors)}, 401
#auth_routes.route('/unauthorized')
def unauthorized():
"""
Returns unauthorized JSON when flask-login authentication fails
"""
return {'errors': ['Unauthorized']}, 401
login_form.py
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired, Email, ValidationError
from app.models import User
def user_exists(form, field):
# Checking if user exists
email = field.data
user = User.query.filter(User.email == email).first()
if not user:
raise ValidationError('Email provided not found.')
def password_matches(form, field):
# Checking if password matches
password = field.data
email = form.data['email']
user = User.query.filter(User.email == email).first()
if not user:
raise ValidationError('No such user exists.')
if not user.check_password(password):
raise ValidationError('Password was incorrect.')
class LoginForm(FlaskForm):
email = StringField('email', validators=[DataRequired(), user_exists])
password = StringField('password', validators=[
DataRequired(), password_matches])
users.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { environment } from 'src/environments/environment';
#Injectable({
providedIn: 'root'
})
export class UsersService {
constructor(
private httpClient: HttpClient
) { }
loginUser(credentials: any) {
console.log("log in clicked")
return this.httpClient.post(`${environment.apiUrl}/auth/login`, {
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(credentials),
});
};
getUser(username: string) {
return this.httpClient.get(`${environment.apiUrl}/users/${username}`, { observe: 'response' })
};
}

Related

Is there any way that I can create a login system using prisma-client-py, flask-login & flask?

I am attempting to create a control panel only using prisma-client-python, flask-login & flask as the primary webserver. I have successfully managed to create the routes, as well as built the registration screen & have also granted prisma access to the database. When I try to use the route,
Here is my code for the login route:
`
from flask import Blueprint, request, render_template
from prisma.models import User
from flask_login import login_user
login_blueprint = Blueprint('login', __name__ , template_folder='../pages/')
#login_blueprint.route('/', methods=['GET','POST'])
def list_create():
if request.method == 'GET':
return render_template('login.html')
if request.method == 'POST':
data = request.form
if data is None:
return
email = data.get('email')
password = data.get('password')
if email is None or password is None:
return {"error": "You need to provide email and password"}
user = User.prisma().find_many(where={'email': email, 'password': password},)
print(user)
return login_user(user)
`
Here is my code for the registration route:
`
from flask import Blueprint, request, render_template
from prisma.models import User
user_blueprint = Blueprint('register', __name__ , template_folder='../pages/')
#user_blueprint.route('/', methods=['GET','POST'])
def list_create():
if request.method == 'POST':
data = request.form
if data is None:
return
name = data.get('username')
email = data.get('email')
password = data.get('password')
if name is None or email is None:
return {"error": "You need to provide name and email"}
user = User.prisma().create(data={'email': email, 'username': name, 'password': password})
return dict(user)
return render_template('register.html')
`
here is my prisma schema:
`
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator db {
provider = "prisma-client-py"
interface = "sync"
}
model User {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
email String #unique
password String
username String?
admin Boolean #default(false)
is_active Boolean #default(false)
}
`
& here is my main app.py route.
`
from flask import Flask
from prisma import Prisma, register
from routes.register import user_blueprint
from prisma.models import User
from routes.login import login_blueprint
# from routes.post import post_blueprint
db = Prisma()
db.connect()
register(db)
app = Flask(__name__)
#app.route('/', methods=['GET'])
def index():
return {
"ping": "pong"
}
app.register_blueprint(user_blueprint, url_prefix='/register')
app.register_blueprint(login_blueprint, url_prefix='/login')
if __name__ == "__main__":
app.run(debug=True, port=5000, threaded=True)
`
I had tried using login_user(user) as stated in code examples using it. But I keep getting the following error:
AttributeError: 'list' object has no attribute 'is_active'
Does anyone have any idea for what I should to resolve this problem & allow the user to login?
The login route (for which the function is also oddly called list_create) queries the database using find_many - which will return a list of items, not a single item. Flask's login() expects a single user, not a list. The exception makes sense, as the login function is provided with a list of user(s), not a user object.
A simple fix can be:
#login_blueprint.route('/', methods=['GET','POST'])
def list_create():
...
user = User.prisma().find_many(where={'email': email, 'password': password},)
if user and len(user) == 1:
return login_user(user[0])
return {"error": "Authentication error, or user does not exist"}
Alternatively, you can try using find_unique as per Prisma's documentation.

flask_jwt_extended.exceptions.NoAuthorizationError: Missing Authorization Header - Authorization not working

I am using flask_jwt_extended for jwt authentication in my flask web application. After the user enters email and password, I make a token using create_access_token and then redirect to another link which can only be accessed with #jwt_required.
app.py file. Notice if the way of importing jwt from user.py file like this is correct.
from flask import Flask
from flask_restful import Api
from resources.organization import OrganizationResourceList, OrganizationResource
from resources.user import LoginResource, user_list, User, jwt
app = Flask(__name__)
app.config['SECRET_KEY'] = '_rV;He_7Bz8TVvA'
app.config['JWT_TOKEN_LOCATION'] = ['headers']
jwt.init_app(app)
api = Api(app)
user_list.append(User(name="Admin User", email="admin#test.com", password="12345", photo="", user_type="host"))
# Authorization
api.add_resource(LoginResource, '/login')
# Organization
api.add_resource(OrganizationResourceList, '/organizations')
if __name__ == '__main__':
app.run(port=5000, debug=True)
user.py file containing LoginResource This is where I am creating token.
from flask import request, Response, render_template, redirect
from flask_restful import Resource
from models.user import User, user_list
from passlib.hash import sha256_crypt
from flask_jwt_extended import create_access_token, create_refresh_token, JWTManager
jwt = JWTManager()
class LoginResource(Resource):
def post(self):
req = request.form
email = req.get("email")
user = [x for x in user_list if x.email == email]
if user:
user = user[0]
password = sha256_crypt.verify(req.get("password"), user.password)
if user and password:
access_token = create_access_token(identity=user.id)
refresh_token = create_refresh_token(user.id)
redir = redirect('/organizations')
redir.headers['Authorization'] = "Bearer %s" % access_token
return redir
return redirect("/login")
Interestingly, when I debug the app, I see the headers of redirect as shown.
organization.py file containing OrganizationResourceList class
from flask import request, Response, render_template
from flask_restful import Resource
from models.organization import Organization, organization_list
from flask_jwt_extended import jwt_required, get_jwt_identity
class OrganizationResourceList(Resource):
#jwt_required()
def get(self):
current_user = get_jwt_identity()
sample_org = Organization(
name='Bin Yousef',
description='My main working company in Qatar',
photo=''
)
data = []
for organization in organization_list:
data.append(organization.data)
return Response(response=render_template('organization/index.html', organizations=data))
After hours of searching, I am still not able to get rid of the error :( Please help

AttributeError: 'list' object has no attribute 'is_active'

I am building a website using Flask and when I try to log in and signup I get this error AttributeError: 'list' object has no attribute 'is_active'
an error like this appears when I have used login_user in the flask_login library
here I use firestore database
I have tried various solutions on StackOverflow but none of them worked, I'm very confused now
this is my code
__ini__.py
from flask import Flask
from flask_login import UserMixin
from flask_login import LoginManager
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = 'adjadlkahd'
db = connect_database()
from .views import views
from .auth import auth
from .models import User
#check user login
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#create user model
#login_manager.user_loader
def load_user(id):
return User.get_user_id(id)
#register blueprints
app.register_blueprint(views, url_prefix='/')
app.register_blueprint(auth, url_prefix='/')
return app
cred = credentials.Certificate("websites\serviceAccountKey.json")
firebase_admin.initialize_app(cred)
def connect_database():
db = firestore.client()
return db
auth.py
from flask import Blueprint, render_template, request, redirect, url_for
from .models import User
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import login_user, login_required, logout_user, current_user
auth = Blueprint('auth', __name__)
#auth.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
email = request.form.get('email')
password = request.form.get('password')
user = User.log_in(email)
if user:
if check_password_hash(user[0].to_dict()['password'], password):
login_user(user, remember=True)
redirect(url_for('views.home'))
else:
return "<h1>paass salah</h1>"
else:
return "<h1>user tidak ada</h1>"
return render_template('login.html')
#auth.route('/logout')
#login_required
def logout():
logout_user()
return redirect(url_for('auth.login'))
#auth.route('/signup', methods=['GET', 'POST'])
def signup():
if request.method == 'POST':
username = request.form.get('username')
email = request.form.get('email')
password = request.form.get('password')
if User.check_user(email):
return "<h1>email already exist</h1>"
new_user = User(username=username, email=email,
password=generate_password_hash(password)).create_user()
login_user(new_user, remember=True)
return redirect(url_for('views.home'))
return render_template('signup.html')
models.py
from flask_login import UserMixin
from . import connect_database
import uuid
db = connect_database()
class User(UserMixin):
def __init__(self, username, email, password):
self.username = username
self.email = email
self.password = password
def create_user(self):
db.collection('user').document(self.username).set({
'id' : str(uuid.uuid4()),
'username': self.username,
'email': self.email,
'password': self.password
})
def log_in(email):
user = db.collection('user').where('email', '==', email).get()
return user
def check_user(email):
user = db.collection('user').where('email', '==', email).get()
return bool(user)
def get_user_id(id):
return db.collection('user').document(id).get()
views.py
from flask import Blueprint
from flask_login import login_required, current_user
views = Blueprint('views', __name__)
#views.route('/')
#login_required
def home():
return "<h1>logged in</h1>"
For flask login to work you need to have a user class that implements some properties and methods. When you use login_user method the argument should be an instance of that user class.
make user that your method def log_in(email) returns a user object not a list.
def log_in(email):
user = db.collection('user').where('email', '==', email).get()
return user # <-- most probably is a list.
Read the items form the user collection
Create an instance of the user class
fill the properties of the user class from the collection
return the instance

Flask - MongoDB - Protect routes

I am new to Flask and I built a basic web app using Flask. This app will be used by a single user. The user must be connected in order to access any routes. What would be the easiest and most secure way to create new routes on my app and make sure that the user is logged in before they are able to access the page?
I added this route and I am able to access the page even if I am logged in.
#login_required
#app.route('/secret')
def secret():
return "hello world"
app.py
from flask import Flask, render_template, url_for, request, session, redirect
from flask_pymongo import PyMongo
import bcrypt
app = Flask(__name__)
app.config['MONGO_DBNAME'] = xxx'
app.config['MONGO_URI'] = 'xxxx'
mongo = PyMongo(app)
#app.route('/')
def index():
if 'username' in session:
return 'You are logged in as ' + session['username']
return render_template('index.html')
#app.route('/login', methods=['POST'])
def login():
users = mongo.db.users
login_user = users.find_one({'name' : request.form['username']})
if login_user:
if bcrypt.hashpw(request.form['pass'].encode('utf-8'), login_user['password']) == login_user['password']:
session['username'] = request.form['username']
return redirect(url_for('index'))
return 'Invalid username/password combination'
#app.route('/register', methods=['POST', 'GET'])
def register():
if request.method == 'POST':
users = mongo.db.users
existing_user = users.find_one({'name' : request.form['username']})
if existing_user is None:
hashpass = bcrypt.hashpw(request.form['pass'].encode('utf-8'), bcrypt.gensalt())
users.insert({'name' : request.form['username'], 'password' : hashpass})
session['username'] = request.form['username']
return redirect(url_for('index'))
return 'That username already exists!'
return render_template('register.html')
#app.route('/logout')
def logout():
session.pop('username', None)
return render_template('index.html')
if __name__ == '__main__':
app.secret_key = 'mysecret'
app.run(debug=True, port='3500')
You can use the flask-login module for this. It handles user authentication, allowing routes to be protected with the #login_required decorator.
I recommend reading the documentation, as you need to provide a class with certain properties to represent your users and you need to implement a method that returns a user based on a given identifier.
When a user is logged in, the templates can access the current_user variable and it's properties (as defined by you; name, email etc).
Here is a simple example of the python code (I have not included the static files or templates).
from flask import Flask, render_template, request, url_for, request, redirect, abort
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from flask_pymongo import PyMongo
from flask_bcrypt import Bcrypt
from urllib.parse import urlparse, urljoin
import sys
# Import User classes
from user import User, Anonymous
# Create app
app = Flask(__name__)
# Configuration
app.config['MONGO_DBNAME'] = 'database_name'
app.config['MONGO_URI'] = 'mongo_database_uri'
app.secret_key = 'change this before production'
# Create Pymongo
mongo = PyMongo(app)
# Create Bcrypt
bc = Bcrypt(app)
# Create login manager
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.anonymous_user = Anonymous
login_manager.login_view = "login"
# ROUTES
#app.route('/')
def index():
return render_template('index.html')
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
if current_user.is_authenticated:
return redirect(url_for('/index'))
return render_template('login.html')
users = mongo.db.users
user_data = users.find_one({'email': request.form['email']}, {'_id' : 0 })
if user_data:
if bc.check_password_hash(user_data['password'], request.form['pass']):
user = User(user_data['title'], user_data['first_name'], user_data['last_name'], user_data['email'], user_data['password'], user_data['id'])
login_user(user)
#Check for next argument (direct user to protected page they wanted)
next = request.args.get('next')
if not is_safe_url(next):
return abort(400)
return redirect(next or url_for('profile'))
return 'Invalid email or password'
#app.route('/register', methods=['POST', 'GET'])
def register():
if request.method == 'POST':
users = mongo.db.users
existing_user = users.find_one({'email' : request.form['email']}, {'_id' : 0 })
if existing_user is None:
logout_user()
hashpass = bc.generate_password_hash(request.form['pass']).decode('utf-8')
new_user = User(request.form['title'], request.form['first_name'], request.form['last_name'], request.form['email'], hashpass)
login_user(new_user)
users.insert_one(new_user.dict())
return redirect(url_for('profile'))
return 'That email already exists!'
return render_template('register.html')
#app.route('/profile', methods=['GET'])
#login_required
def profile():
return render_template('profile.html')
#app.route('/list', methods=['GET'])
#login_required
def list():
#if current_user.id:
log(current_user.is_authenticated)
all_users = mongo.db.users.find({}, {'_id' : 0 })
return render_template('list.html', users = all_users)
#app.route('/logout', methods=['GET'])
#login_required
def logout():
logout_user()
return redirect(url_for('index'))
# Login Manager requirements
#login_manager.user_loader
def load_user(userid):
# Return user object or none
users = mongo.db.users
user = users.find_one({'id': userid}, {'_id' : 0 })
if user:
log(user)
return User(user['title'], user['first_name'], user['last_name'], user['email'], user['password'], user['id'])
return None
# Safe URL
def is_safe_url(target):
ref_url = urlparse(request.host_url)
test_url = urlparse(urljoin(request.host_url, target))
return test_url.scheme in ('http', 'https') and \
ref_url.netloc == test_url.netloc
# Run app
if __name__ == '__main__':
app.run(debug=True)
I have a functioning basic template app using flask, flask-login and flask-pymongo at https://github.com/chriswilson1982/flask-mongo-app

Internal Flask POST requests to Flask-Jwt /auth endpoint doesn't succeed

I come to you today with a problem that seems to be annoying and bother me for 1 week (maybe more).
I implemented Flask and Flask-JWT to create a Token and use it in different parts of my web-app.
The process is : The user puts is credentials on the form and when he's logged a token is created by making a POST request to the Flask-JWT /auth endpoint.
The problem is :
When the user has loged-in, the token creation part of the code (POST request to /auth endpoint) seems to be in an endless loop.
The code stop at : "r = requests.post(url, headers=headers, data=payload)"
The funny part is that if a user login and after go to the /auth endpoint, it has the token created.
Someone already had this problem ?
Thank you
project/config.py
JWT_EXPIRATION_DELTA = timedelta(seconds=900)
JWT_AUTH_URL_RULE = "/api/v1/auth"
SECURITY_PASSWORD_HASH = 'pbkdf2_sha512'
SECURITY_TRACKABLE = True
SECURITY_PASSWORD_SALT = "xxxx"
WTF_CSRF_ENABLED = True
WTF_CSRF_SECRET_KEY = "xxxx"
project/app/init.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_required
from flask_bcrypt import Bcrypt
from flask_security import Security, SQLAlchemyUserDatastore, \
UserMixin, RoleMixin, login_required
from flask_jwt import JWT, jwt_required
import os
app = Flask(__name__)
app.config.from_object('config')
bcrypt = Bcrypt(app)
db = SQLAlchemy(app)
# To have random secret key
secret_key = os.urandom(24)
app.secret_key = secret_key
from textr import views, models
from search_number import views
from buy_number import views
from users import views, models
from sms_receiver import views, models
from sms_sender import views, models
from phone_number import models, views
from users.models import User, Role
# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
#login_manager.user_loader
def load_user(user_id):
return User.query.filter(User.id == int(user_id)).first()
from textr.tools import retreive_user, verify_password
def authenticate(username, password):
user = retreive_user(username)
if verify_password(username, password):
return user
def identity(payload):
return User.query.filter(User.id == payload['identity']).scalar()
jwt = JWT(app, authenticate, identity)
project/app/users/views.py
from flask_jwt import jwt_required, JWT
from models import User
from error_handling import error_400
from flask import Flask, request, render_template, jsonify, session, redirect, url_for, flash
import json
import requests
#app.route("/api/v1/login", methods=["GET", "POST"])
def login():
error = None
if request.method == 'POST':
json_data = request.json
if not json_data:
username = request.form['username']
password = request.form['password']
else:
username = json_data['username']
password = json_data['password']
if not check_user_present(username):
return error_400('Error', 'User not found', 404)
if verify_password(username, password):
flash('Logged in successfully.')
user = retreive_user(username)
login_user(user)
# Infos to create POST request for Token
payload = ({'username':username, 'password':password})
url = "http://127.0.0.1:8080/api/v1/auth"
headers = {'Content-Type': 'application/json', 'charset': 'utf-8'}
# Token creation
r = requests.post(url, headers=headers, data=payload)
response = r.json()
if (r.status_code is 200):
token = response['user']['authentication_token']
session['api_session_token'] = token)
else:
flash('Wrong credentials!')
return error_400('Error', 'Wrong credentials', 401)
return render_template('users/login.html')

Categories