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 id
, username
, password
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:
- Python flask login logout example
- Python Flask Login Logout with Remember Me Option
- jQuery AJAX based Login Logout using Python Flask MySQL
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 rest.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.
Thank you very much. Works like a charm!
Also,
from werkzeug.security import check_password_hash is what worked for me
from werkzeug import check_password_hash seems to have been deprecated.
Great work. Looking forward to learning some new skills from your platform
when i ran app.py (and not main.py since that does not exist in this project) alI get it is:
Process finished with exit code 0
I do not get a link to http://localhost:5000/ as expected. http://localhost:5000/ does not respond in browser either.
New to python and flask please advice
You need to run rest.py instead of main.py