Introduction

We will create REST APIs to allow users login and logout from an application using Python and Flask. We have seen in another tutorial how to login and logout from an application where UI or front end was built using flask template file but here we are not providing any UI or front end but UI or front end can be built using any technology or framework. So it is decoupled from the UI or front end technology.

We know when we need to restrict users from accessing protected area of the application. In addition to authentication you can also implement authorization based on user’s role.

Prerequisites

Python 3.7.4, MySQL 8.0.17, Flask 1.1.1

Creating MySQL table

Create a table called user in the MySQL database using the following structure.

The following table has idusernamepassword columns.

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(45) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Storing Sample User

To make the example Python Flask REST API login logout example workable, we have added one row with user information into table.

It is always better to store password in encrypted format instead of clear text due to security reasons.

The password is roy for the password field’s encrypted value in the table.

insert into `user`(`username`, `password`) 
values ('roy', 'pbkdf2:sha256:150000$k1Ud5dzh$d0347f416e89ea486b33c988c9be65730329b2dd6d712f73c9920103a006a82e');

Creating Project Directory

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

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

Related Posts:

Configuring Application

We will configure application through flask framework.

Create a file called app.py with the below code.

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

We have also configured the session timeout – 10 minutes because flask expires session once you close the browser unless you have a permanent session.

We have also configured CORS to allow cross origin requests, otherwise you may get cross origin error.

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
app.secret_key = "secret key"
app.config['PERMANENT_SESSION_LIFETIME'] =  timedelta(minutes=10)
CORS(app)

Database Configuration

We create the below db_config.py Python script to setup the MySQL database configurations for connecting to database.

We need to configure database connection with flask module and that’s why we 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)

Configuring REST Endpoint

Now we will create REST endpoint that will be used to authenticate user into the server.

We show a successful message once a user is successfully authenticated with correct credentials.

Only with successful operation we send response status 200 otherwise we send 400 or 401 as bad request or unauthorized with error messages.

We have defined endpoints for root, login and logout to access protected area, authenticate using credentials and logout from the application, respectively.

WARNING: session violates RESTful.

You may want to know why check_password_hash() is required?

Create a file rest.py with the below source code.

import pymysql
from app import app
from db import mysql
from flask import jsonify, request, session
from werkzeug import check_password_hash
		
@app.route('/')
def home():
	if 'username' in session:
		username = session['username']
		return jsonify({'message' : 'You are already logged in', 'username' : username})
	else:
		resp = jsonify({'message' : 'Unauthorized'})
		resp.status_code = 401
		return resp

@app.route('/login', methods=['POST'])
def login():
	conn = None;
	cursor = None;
	
	try:
		_json = request.json
		_username = _json['username']
		_password = _json['password']
		
		# validate the received values
		if _username and _password:
			#check user exists			
			conn = mysql.connect()
			cursor = conn.cursor()
			
			sql = "SELECT * FROM user WHERE username=%s"
			sql_where = (_username,)
			
			cursor.execute(sql, sql_where)
			row = cursor.fetchone()
			
			if row:
				if check_password_hash(row[2], _password):
					session['username'] = row[1]
					#cursor.close()
					#conn.close()
					return jsonify({'message' : 'You are logged in successfully'})
				else:
					resp = jsonify({'message' : 'Bad Request - invalid password'})
					resp.status_code = 400
					return resp
		else:
			resp = jsonify({'message' : 'Bad Request - invalid credendtials'})
			resp.status_code = 400
			return resp

	except Exception as e:
		print(e)

	finally:
		if cursor and conn:
			cursor.close()
			conn.close()
		
@app.route('/logout')
def logout():
	if 'username' in session:
		session.pop('username', None)
	return jsonify({'message' : 'You successfully logged out'})
		
if __name__ == "__main__":
    app.run()

Deploying the Application

Now navigate to the project’s root directory using command line tool and execute the command python 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.

Testing the Application

We will test our application using REST client tool – Chrome extension REST client. You can also use Postman or any other REST client tool for testing.

You may also do client side programming using Angular, React or any front end technology to call the above REST endpoint.

Root URI

When you access the root URI without authenticating.

URL: http://localhost:5000/

Method: GET

Response:

{
   "message": "Unauthorized"
}

Authentication

Authenticate using credentials roy/roy.

URL: http://localhost:5000/login

Method: POST

Request Body:

{
  "username" : "roy",
  "password" : "roy"
}

Response:

{
  "message": "You are logged in successfully"
}

Accessing Root URI

Now when you access again the root URI or URL, you will be able to access it.

URL: http://localhost:5000/

Method: GET

Response:

{
    "message": "You are already logged in",
    "username": "roy"
}

Logout

Logout using the following URL.

URL: http://localhost:5000/logout

Method: GET

Response:

{
   "message": "You successfully logged out"
}

You can also test by providing wrong credentials or not sending any credentials.

Source Code

Thanks for reading.

Leave a Reply

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