AJAX Based Login Logout Using Flask MySQL

Login Logout App

I will create an example to show you how to build jQuery AJAX based login logout using Python Flask MySQL. Flask is a light-weight framework for building rapid web application whose data are stored into MySQL database server. I will use HTML, AJAX technique using jQuery technology to call the REST API for login and logout endpoints. I will validate the credentials on server side code, i.e., using Python and Flask.

I will send http status code 200 on success and status code 400 for invalid credentials. I will use template (Jinja) from Flask API to render the login page where input fields will be displayed for entering email address and password. I will use MySQL database where user details are already stored to validate the user who wants to login.

Prerequisites

Python 3.8.0/3.11.5, Flask 1.1.1/2.3.3, MySQL 8.0.17/8.1.0

User Details

Let’s assume that you already have the user details stored in your MySQL database.

Sample Table and User

The table structure where user details are stored:

CREATE TABLE `user` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NULL,
  `email` varchar(50) NULL,
  `pwd` varchar(255) NULL,
  `admin` tinyint DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sample data for the above table:

insert  into `user`(`id`,`name`,`email`,`pwd`,`admin`) values 
(1,'S Roy','roy@email.com','pbkdf2:sha256:150000$k1Ud5dzh$d0347f416e89ea486b33c988c9be65730329b2dd6d712f73c9920103a006a82e',1);

Project Directory

Create a project root directory called python-flask-ajax-mysql-login-logout as per your chosen location.

I may not mention the project’s root directory name in the subsequent sections but I will assume that I am creating files with respect to the project’s root directory.

Configure Flask

I here configure application through flask framework. Create a file called app.py with the below code.

from flask import Flask

app = Flask(__name__)
app.secret_key = "secret key"

Here I need to assign secret key otherwise session will not work in Python. The secret key, ideally, should be in an encrypted format.

Ideally you want to configure the session timeout because flask expires session once you close the browser unless you have a permanent session. For this example, I have not configured any session timeout.

Database Configuration

I will create the below db_config.py Python script to setup the MySQL database configurations for connecting to database and storing user information into user table under roytuts database.

I need to configure database connection with flask module and that’s why I have imported app module and setup the MySQL configuration with flask module.

Make sure to change the database configuration values according to your database setup.

from app import app
from flaskext.mysql import MySQL

mysql = MySQL()
 
# MySQL configurations
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = 'root'
app.config['MYSQL_DATABASE_DB'] = 'roytuts'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)

User Information Validation

I am going to fetch the user information from database table and validate the input user’s credentials.

Create a Python script dao.py with the below source code.

In the below script we have two functions – login()

import pymysql
from db_config import mysql
#from werkzeug import check_password_hash version 1.x
from werkzeug.security import check_password_hash # version 2.x, 3.x
			
def login(email, pwd):
	conn = None;
	cursor = None;
	
	try:
		conn = mysql.connect()
		cursor = conn.cursor()
		
		sql = "SELECT email, pwd FROM user WHERE email=%s"
		sql_where = (email,)
		
		cursor.execute(sql, sql_where)
		row = cursor.fetchone()
		
		if row:
			if check_password_hash(row[1], pwd):
				return row[0]
		return None

	except Exception as e:
		print(e)

	finally:
		if cursor and conn:
			cursor.close()
			conn.close()

The above login() function simply fetches user information from the database table for the given user’s credentials and validates.

REST Endpoint

As I said at the beginning that I will build REST API to login users into the system.

Create a Python script rest.py with the following source code.

In the below REST endpoint – /login, I will get the input values and if they are empty or invalid then I will send http status 400 – bad request parameters.

The REST endpoint – /logout, logs out a user of the application.

import dao
from app import app
from flask import jsonify, request, session
		
@app.route('/login', methods=['POST'])
def login():
	_json = request.json
	#print(_json)
	_username = _json['username']
	_password = _json['password']
	
	if _username and _password:
		user = dao.login(_username, _password)
		
		if user != None:
			session['username'] = user
			return jsonify({'message' : 'User logged in successfully'})

	resp = jsonify({'message' : 'Bad Request - invalid credendtials'})
	resp.status_code = 400
	return resp

@app.route('/logout')
def logout():
	if 'username' in session:
		session.pop('username', None)
	return jsonify({'message' : 'You successfully logged out'})

AJAX For Front-End

I mentioned in the beginning that I am going to use AJAX technique with jQuery to call the REST API.

So here is the code that will allow a user login, provided that user inputs all the required fields with proper format.

Related Posts:

In the below code we get the input values from login page once user click on submit button.

I will validate the email address and password.

On successful login I will hide the login page, login/sign up links and show success message.

On successful logout I will show the login/sign up links.

I have stored the user session in localStorage() function at client side. Here you may find out other mechanism to track your user’s session.

The below code is written in a file auth.js under static/js folder. This is a convention that you put your static resources under static folder.

$(document).ready(function() {
	var isLoggedIn = localStorage.getItem('loggedin');
	
	if(isLoggedIn == 1) {
		$('#sign').hide();
		$('#loginform').hide();
		$('#signupform').hide();
		$('#logoff').show();
	} else {
		$('#sign').show();
		$('#logoff').hide();
	}
	
	$('#loginSubmit').on('click', function(e) {
		e.preventDefault();
		
		var email = $('#email').val();
		var pwd = $('#password').val();
		
		var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/i;
		
		if(email != "" && pwd != "" ) {
			if(!regex.test(email)) {
				$('#msg').html('<span style="color: red;">Invalid email address</span>');
			} else {
				$.ajax({
					method: "POST",
					url: '/login',
					contentType: 'application/json;charset=UTF-8',
					data: JSON.stringify({'username': email, 'password': pwd}),
					dataType: "json",
					success: function(data) {
						localStorage.setItem('loggedin', 1);
						
						$('#sign').hide();
						$('#loginform').hide();
						$('#logoff').show();
						$('#msg').html('<span style="color: green;">You are logged in</span>');
					},
					statusCode: {
						400: function() {
							$('#msg').html('<span style="color: red;">Bad request - invalid credentials</span>');
						}
					},
					error: function(err) {
						console.log(err);
					}
				});
			}
		} else {
			$('#msg').html('<span style="color: red;">Invalid username and password</span>');
		}
	});
	
	$('#logout').on('click', function(e) {
		e.preventDefault();
		
		$.ajax({
			url: '/logout',
			dataType: "json",
			success: function(data) {
				localStorage.setItem('loggedin', 0);
				$('#sign').show();
				$('#logoff').hide();
				$('#msg').html('<span style="color: green;">You are logged off</span>');
			},
			error: function(err) {
				console.log(err);
			}
		});
	});
});

Template File

As you need to display login page with input fields, so you need to have a template page. The template page is written with simple HTML tags.

By convention, the template page is put under templates directory.

Create a template file called login.html and put the below source code into it.

I have also put another template file for home page – index.html.

If you do not want to repeat common sections, such as header, footer, left then you can read how to work with parent and child templates in flask API.

I have a sign up link in this application but the functionality has not been implemented here and you can read the tutorial on jQuery AJAX based Registration System using Python Flask MySQL.

File – login.html

The content for login.html is given below:

<!DOCTYPE html>
<html>
	<head>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>jQuery AJAX Login Logout using Python Flask MySQL</title>
		<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
		<script type="text/javascript" src="{{ url_for('static', filename='js/auth.js') }}"/>
		<script type="text/javascript">
			$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
		</script>
	</head>
<body>

	<div>
		<ul style="list-style: none; float: left;">
			<li><a href="{{ url_for('.home_page') }}">Home</a></li>
			<div id="sign">
				<li><a href="#">Sign Up</a></li>
				<li><a href="{{ url_for('.login_page') }}">Login</a></li>
			</div>
			<div id="logoff" style="display: none;">
				<li><a href="#" id="logout">Log Off</a></li>
			</div>
		</ul>
	</div>

	<div style="width: 500px; margin: auto;">
	
		<div id="msg"></div>
		<div style="clear: both;"></div>
		<div id="loginform">
			<h2>Login</h2>
			<dl>
				<p>
					<input id="email" value="" type="text" placeholder="Email" required>
				</p>
				<p>
					<input id="password" value="" type="password" placeholder="Password" autocomplete="off" required>
				</p>
			</dl>
			<p>
				<input type="button" id="loginSubmit" value="Submit">
			</p>
		</div>
		
	</div>
	
</body>
</html>

File – index.html

The content for home page (index.html) is given below:

<!DOCTYPE html>
<html>
	<head>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>jQuery AJAX Login Logout using Python Flask MySQL</title>
		<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
		<script type="text/javascript" src="{{ url_for('static', filename='js/auth.js') }}"/>
		<script type="text/javascript">
			$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
		</script>
	</head>
<body>

	<div>
		<ul style="list-style: none; float: left;">
			<li><a href="{{ url_for('.home_page') }}">Home</a></li>
			<div id="sign">
				<li><a href="#">Sign Up</a></li>
				<li><a href="{{ url_for('.login_page') }}">Login</a></li>
			</div>
			<div id="logoff" style="display: none;">
				<li><a href="#" id="logout">Log Off</a></li>
			</div>
		</ul>
	</div>

	<div style="width: 500px; margin: auto;">
	
		This is a home page
		
	</div>
	
</body>
</html>

Main Python Script

The below code will render the login/home page on when clicked on Login/Home link respectively. On application startup home page is displayed.

Create a Python script main.py with the following source code.

import rest
from app import app
from flask import render_template

@app.route('/')
def home_page():
	return render_template('index.html')
	
@app.route('/login/page')
def login_page():
	return render_template('login.html')
		
if __name__ == "__main__":
    app.run()

Testing the Login Logout Application

Now navigate to the project directory and execute the command python main.py or simply main.py, your server will be started on default port 5000.

If you want to change the port then you can change the line app.run() to app.run(port=5001), where 5001 is the new port.

Now you can hit the URL http://localhost:5000 on your browser and you will see sign up page is displayed on the browser.

jquery based login logout using python flask mysql

Clicking on Login link will display the following page:

jquery ajax based login logout using python flask mysql

As you see the pages are not styled so you can apply css to make the looks better of the pages.

Once successful login (credentials – roy@email.com/roy) you will see the following page:

jquery ajax based login logout using python flask mysql

Notice in the above image that Sign up and Login links are not displayed once a user logged in.

On clicking on Log Off link you will see again all links.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *