Designing A Login Register and User Authentication System in Python

Rampal Punia
7 min readMar 31, 2023

--

Photo by Aziz Acharki on Unsplash

Introduction

Password security is a critical aspect of cybersecurity. Passwords are essential for protecting our online identities and confidential data. To ensure password security, it is essential to use a robust password policy and take appropriate measures to safeguard them.

In this blog post, we will look at a Python script that implements a basic password management system that can help to understand how to approach creating secure user passwords.

The Python script provides a basic user interface that allows users to register and log in to the system. The system generates a random password that meets specific requirements for new users during the registration process.

Additionally, the system stores the user’s login credentials in a file after hashing the password using the SHA-256 algorithm. Let’s examine each section of the Python script in more detail.

Coding: Login Register and User Authentication Script

Importing Modules and Placing Constants

First, we import the necessary modules in the script.

import secrets
import string
import hashlib
from getpass import getpass

The secrets module is used to generate random passwords. The string module provides a list of ASCII letters and digits that are used to generate the random password.

The hashlib module is used to hash the password before saving it to the user details file. Finally, the getpass module is used to hide the password input from the terminal.

USER_DETAILS_FILEPATH = "users.txt"

PUNCTUATIONS = "@#$%&"

DEFAULT_PASSWORD_LENGTH = 12

INVALID_LENGTH_MESSAGE = f'''
Password length must be between 8 and 16.
Password length must be a number.
Generating password with default length of {DEFAULT_PASSWORD_LENGTH} characters.
'''

The USER_DETAILS_FILEPATH constant holds the path to the file that stores the user details. The PUNCTUATIONS constant holds the selected punctuation that can be used in the randomly generated password.

The DEFAULT_PASSWORD_LENGTH constant holds the default password length if the user doesn't provide one. The INVALID_LENGTH_MESSAGE constant holds the error message to display to the user if the user inputs a password length that is not in the range (8-16) and not an integer.

Generate Password

def generate_password(length=12):
characters = string.ascii_letters + string.digits + PUNCTUATIONS
pwd = ''.join(secrets.choice(characters) for _ in range(length))
return pwd

The generate_password function generates a random password of the required length (default length is 12). The password consists of ASCII letters, digits, and selected punctuation characters.

In this script, instead of using all the punctuation from string.punctuation I have decided to use only 5 commonly used punctuations stored in PUNCTUATIONS variable. Of course, you can use all or modify them as per your requirements.

Hashing the Generated Password

def hash_password(pwd):
"""Hash a password using SHA-256 algorithm"""
pwd_bytes = pwd.encode('utf-8')
hashed_pwd = hashlib.sha256(pwd_bytes).hexdigest()
return hashed_pwd

The hash_password function takes a password as input, encodes it to bytes, and hashes it using the SHA-256 algorithm. The hashed password is returned as a hexadecimal string.

Saving the User Details in a File

def save_user(username, hashed_pwd):
"""Save user-details to the users detail file"""
with open(USER_DETAILS_FILEPATH, "a") as f:
f.write(f"{username} {hashed_pwd}\n")

The save_user function saves the user's details to a file specified by USER_DETAILS_FILEPATH variable. The username and hashed password are written to the file as a space-separated string.

Important Note: The user details are saved in a plain text file (users.txt) without any encryption or other security measures. This can be a security risk if the file is accessed by an unauthorized user or if the file is stored on an insecure system.

Check If The User Exists

def user_exists(username):
try:
with open(USER_DETAILS_FILEPATH, "r") as f:
for line in f:
parts = line.split()
if parts[0] == username:
return True
except FileNotFoundError as fl_err:
print(f"{fl_err.args[-1]}: {USER_DETAILS_FILEPATH}")
print(f"System will create file: {USER_DETAILS_FILEPATH}")
return False

The user_exists function checks if a user with the specified username already exists in the user details file. If the script is run first time it will catch the file not find error and give the user same message. The users.txt file to save user details will be created after user password is created with save_user() function.

It returns True if the user exists, otherwise False.

Authenticating User

def authenticate_user(username, password):
with open(USER_DETAILS_FILEPATH, "r") as f:
for line in f:
parts = line.split()
if parts[0] == username:
hashed_password = parts[1]
if hashed_password == hash_password(password):
return True
else:
return False
return False

The authenticate_user function checks if the specified password matches the hashed password stored for the user with the specified username in the user details file. It returns True if the password is correct, otherwise False.

Important Note: The authenticate_user() function reads the user details from the USER_DETAILS_FILEPATH file and checks if the password matches the hashed password in the file. While this approach is simple and straightforward, it may not be secure enough for a production system. For example, it does not use salting to further protect against attacks like dictionary attacks and rainbow table attacks.

Here is a basic example to demonstrate the basic use of adding salt to hash a password to make it more secure.

import hashlib

password = "password123"
salt = "randomsaltvalue"
hashed_password = hashlib.sha256(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()

Validate input function

def validate_input(password_length):
try:
password_length = int(password_length)
if password_length < 8 or password_length > 16:
raise ValueError("Password length must be between 8 and 16")
return password_length
except ValueError:
print(INVALID_LENGTH_MESSAGE)
return DEFAULT_PASSWORD_LENGTH

The validate_input function is used to validate user input for password length. It ensures that the password length is an integer value between 8 and 16 or that any other error like the input is not an integer.

If the user input is not within the specified range, we are raising a single exception here and that is ValueError exception with a message stored in INVALID_LENGTH_MESSAGE variable. If the input is valid, it returns the password length as an integer.

Register function

def register():
username = input("Enter username: ")
if user_exists(username):
print("User already exists.")
return
length = input("Enter Auto Generated Password Length (Number 8-16): ")
length = validate_input(length)
password = generate_password(length)

hashed_password = hash_password(password)
save_user(username, hashed_password)
print("User created successfully.")
print("Your password is:", password)

This function prompts the user to enter a username and password length. If the user already exists, the function returns without registering the user. Otherwise, it generates a password and saves the user’s details to the user details file. The generated password is printed on the console.

Login function

def login():
username = input("Enter username: ")
if not user_exists(username):
print("User does not exist.")
return

password = getpass("Password: ")
if not authenticate_user(username, password):
print("Incorrect password.")
return
print("Login successful.")

The login function prompts the user to enter a username and password. It checks if the user exists using the user_exists function.

If the user exists, it checks if the provided password matches the hashed password using the authenticate_user function. If the authentication is successful, it prints "Login successful" to the console. If the authentication fails, it prints "Incorrect password" to the console.

Main function

def main():
while True:
print("1. Register\n2. Login\n3. Exit")
choice = input("Enter your choice: ")
if choice == "1":
register()
elif choice == "2":
login()
elif choice == "3":
break
else:
print("Invalid choice.")

if __name__ == "__main__":
main()

The main function runs a while loop that repeatedly prompts the user to choose between registering, logging in, or exiting. If the user chooses to register, it calls the register function. If the user chooses to log in, it calls the login function. If the user chooses to exit, the while loop breaks and the program terminates.

if __name__ == “__main__”: construct checks if the current script is being run as the main program. If it is, it calls the main() function.

Complete Code

Photo by Alesia Kazantceva on Unsplash

Running the program

To run the program, open a terminal or command prompt, navigate to the directory where the script is saved, and type python authentication_system.py in the terminal. The program will start running, and the user will be prompted to choose between registering, logging in, or exiting.

Note: Although I have put effort into designing this Secure Password Authentication script to be Pythonic and used secrets, getpass and hashlib modules yet this script can not be used directly in a production environment, mainly due to the reasons explained in Important Notes.

However, this is an import script, designed to understand the basics of a login, register and authentication system. I hope you enjoyed reading this.

Conclusion

In this tutorial, we have learned how to implement a simple authentication system using Python. We used the ‘secrets’ module to generate random passwords, the ‘hashlib’ module to hash passwords, and the ‘getpass’ module to securely get the user’s password input. We also learned how to read from and write to a file using Python’s built-in file-handling functions.

Hey there👋! If you found this tutorial helpful, please show your appreciation by clapping for it! Remember, you can clap multiple times if you like it.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Rampal Punia
Rampal Punia

Written by Rampal Punia

🐍 Leveraging AI ML & Data Science to Engineer Intelligent Solutions | 🚀Computer Vision, NLP & Generative AI Enthusiast | 📈 Empowering Data-Driven Strategies

No responses yet

Write a response