'Flask login authentication fails on validate in production

I'm using flask-login to set up the log-in to a website and I have got it successfully working for when I run it in development via localhost. However, when I run my production website, it seems to fail on form.validate_on_submit() (returning false instead of true, and therefore skipping the login authentication steps) which seems very strange. Sometimes it is fixed if I clear my cache on my browser, but not always.

So far I have only set up the login process - I have manually added the information needed to my sqlalchemy users database as it is currently only running in production in a "beta" sense for a very limited set of users.

Below is the full authentication set up I am currently using. Any information on where I might be going wrong here would be very appreciated.

__init__.py - App set up

import os

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

from my_app.config import SECRET_KEY, SQLALCHEMY_BINDS, SQLALCHEMY_TRACK_MODIFICATIONS

def create_app(test_config=None):
    '''
    More complex and secure app initialisation.
    More info from Flask Tutorial documentation: https://flask.palletsprojects.com/en/2.0.x/tutorial/
    '''
    app = Flask(__name__, instance_relative_config=True)
    
    app.config['SQLALCHEMY_BINDS'] = SQLALCHEMY_BINDS
    app.config['SECRET_KEY'] = SECRET_KEY
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = SQLALCHEMY_TRACK_MODIFICATIONS

    db = SQLAlchemy()
    db.init_app(app)

    app.add_url_rule("/", endpoint="root")
    return app

server.py - App routing

from flask import render_template, redirect, request, url_for, Flask
from flask_login import LoginManager, login_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from my_app import create_app
from my_app.auth import User, login_form

app = create_app()
login_manager = LoginManager()
login_manager.init_app(app)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(user_id)

@app.route('/login', methods=['GET', 'POST'])
def getLogin():

    form = login_form()
    if form.validate_on_submit():
        try:
            user = User.query.filter_by(name=form.username.data).first()
            if check_password_hash(user.password, form.password.data):
                login_user(user, remember=True)

                return redirect('/home')
            else:
                return redirect('/login')
        except Exception as e:
            print(e)
            return redirect('/login')
    return render_template('login.html',
        form=form,
        text='Login',
        btn_action='Login'
        )

auth.py - User model and form definitions

import wtforms
import wtforms.validators as wtfv
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm

db = SQLAlchemy()

class User(UserMixin, db.Model):
    __bind_key__ = 'users'
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(100))

class login_form(FlaskForm):
    username = wtforms.StringField(validators=[wtfv.InputRequired()])
    # when in production, add length requirements to password field, using wtfv.Length(min='',max='')
    password = wtforms.PasswordField(validators=[wtfv.InputRequired()])

Login.html - Login page

<!DOCTYPE html>
<html>
    <head>
        <title>
            MASSAT Dashboard Login Page
        </title>

        <link rel="stylesheet" href='../static/stylesheets/modules/bootstrap.min.css'></link>
        <link rel="stylesheet" href="../static/stylesheets/dashboardLayout.css"/></link>
    

    </head>

    <header class="header">
        <div id="massat_acro" class="logo">
            <a href="/">
                <img src="/static/images/massat-logo.jpg" alt="MASSAT-Logo" height="45" padding="5px"/>
            </a>
        </div>
    </header>
    <body style="background-color:#fcfcfc; overflow-y: scroll;">
        <div style="text-align:center;width:50%;margin:auto;padding:150px">

            <div class="container">
                <h2 style="color:black">Login to the MASSAT dashboard</h2>

                        <form action="{{ request.path }}" method="POST" class="card-body">
                            {{ form.csrf_token }}
                            
                                <input class="form-control" id="username" name="username" placeholder="Username" required="" type="text" value="">

                                <input class="form-control" id="password" name="password" placeholder="Password" required="" type="password" value="">
                                <br>
                                <input class="btn btn-primary" type="submit" value='Login'>
                            
                        </form>

            </div>
        </div>
    </body>
</html>


Solution 1:[1]

You can try using the validator as; (Fields and Form instead of wtfv and FlaskForm)

from wtforms import Form, BooleanField, StringField, PasswordField, validators, TextAreaField

class login_form(Form):
    name = StringField("Name", validators=[validators.Length(min=4, max=30)])
    surname = StringField("Surname", validators=[validators.Length(min=4, max=30)])

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Furkan Y?ld?z