I have created a simple flask authentication
I have deployed it on render
The app runs fine locally
But when in the deployed app, the check_password_hash always returns false
I use mysql on my local machine and the code works fine but it fails when i deploy it on render
I tried changing bcrypt to werkzeug, i checked all the versions on the deployment environment
Registration view
# Registration route
@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == "POST":
username = request.form["username"]
# print(username)-debug
password = request.form["password"]
# bytes_register = password.encode("utf-8")
# print(password)-debug
# create_table_query_mysql = """
# CREATE TABLE IF NOT EXISTS users (
# id SMALLINT(5) AUTO_INCREMENT PRIMARY KEY,
# username CHAR(128) NOT NULL UNIQUE,
# pass_hash CHAR(128) NOT NULL
# )
# """
create_table_query_postgresql = """
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username CHAR(255) NOT NULL UNIQUE,
password_hash CHAR(255) NOT NULL
)
"""
existing_user_query = "SELECT * FROM users WHERE username=%s"
existing_user_username = None
cursor = connection_db.cursor()
cursor.execute(create_table_query_postgresql)
cursor.execute(existing_user_query, (username,))
existing_user_username = cursor.fetchone()
if existing_user_username:
error_message = "Username taken. Please choose a different username"
return render_template("register.html", error_message=error_message)
hashed_password = bcrypt.generate_password_hash(password)
decoded_hashd_password = hashed_password.decode("utf-8")
insert_user_query = (
"INSERT INTO users (username, password_hash) VALUES (%s, %s)"
)
cursor.execute(insert_user_query, (username, decoded_hashd_password))
connection_db.commit()
return render_template("registration_success.html")
return render_template("register.html")
Login view
# Login Route
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username_login = request.form["username"]
password_login = request.form["password"]
# bytes_login = password_login.encode("utf-8")
# create_table_query_mysql = """
# CREATE TABLE IF NOT EXISTS users (
# id SMALLINT(5) AUTO_INCREMENT PRIMARY KEY,
# username CHAR(128) NOT NULL UNIQUE,
# pass_hash CHAR(128) NOT NULL
# )
# """
create_table_query_postgresql = """
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username CHAR(255) NOT NULL UNIQUE,
password_hash CHAR(255) NOT NULL
)
"""
user_query = "SELECT * FROM users WHERE username=%s"
user_data = None
cursor = connection_db.cursor()
cursor.execute(create_table_query_postgresql)
cursor.execute(user_query, (username_login,))
user_data = cursor.fetchone()
hash = user_data[2]
print(hash)
print(password_login)
# hash_bytes = hash.encode("utf-8")
# print(hash_bytes)
check = bcrypt.check_password_hash(hash, password_login)
print(check)
if user_data and check:
user = User(id=user_data[0], username=user_data[1])
login_user(user)
return redirect("/dashboard")
else:
not_valid = "Invalid User"
return render_template("login.html", not_valid=not_valid)
return render_template("login.html")
The error causing part is in the login route
cursor.execute(user_query, (username_login,))
user_data = cursor.fetchone()
hash = user_data[2]
print(hash)
print(password_login)
# hash_bytes = hash.encode("utf-8")
# print(hash_bytes)
check = bcrypt.check_password_hash(hash, password_login)
print(check)
2
Answers
The problem in my code is that the i am using
CHAR
instead ofVARCHAR
The CHAR type in both MySQL and PostgreSQL when defined with a fixed length fills the cell with padding spaces if the string length is less than the fixed length.
When retrieving data from that cell in postgresql, in my code's case, the password hash, the string is returned with padding spaces which is not visible in the console when printed.
But when the check_password_hash() checks for the string with padding spaces, it returns false.
Hence, the check fails.
MySQL also stores the string with padding spaces in CHAR but removes those spaces during retrieval of the string.
I was using MySQL in my local machine. Therefore, it worked fine in my local machine but not on the deployment PostgreSQL database.
The error you’re encountering is coming mainly from your registration view, I can see that you inserted the
decoded_hashd_password
into the database. This in turn causes the error because there is no hash to check against when you runcheck = bcrypt.check_password_hash(hash, password_login)
. Try inserting just thehashed_password
and notdecoded_hashd_password
.