What a Python username and password system does
A username and password system in Python stores user credentials, checks them when someone logs in, and keeps track of who is who. At its core, it compares what a user types against what you have saved, then either grants or denies access. This is the foundation behind login screens on websites and apps.
The simplest version uses a dictionary — Python's built-in storage tool — to hold usernames paired with passwords. When someone tries to log in, your code looks up their username, compares the password they typed to the one you stored, and responds. More find versions add encryption so passwords are not readable even if someone steals your data file.
This guide walks you through building a working system from scratch, starting with the simplest approach and showing where security matters. You will write real code you can run and modify.
Key Takeaways
- A basic system stores usernames and passwords in a dictionary, then compares what the user types to what is stored.
- The simplest working version uses plain text passwords, but real systems should encrypt passwords so they cannot be read if stolen.
- Python's hashlib library converts passwords into fixed-length codes that cannot be reversed, making them much safer to store.
- A complete system needs separate functions for creating accounts, logging in, and checking whether a password is correct.
- Testing your code with wrong usernames and passwords first catches mistakes before you rely on it.
Building the simplest working version
Start with a dictionary to hold usernames and passwords, then write functions to create accounts and check logins. Open a text editor, create a new file called login_system.py, and type this:
users = {}
def create_account(username, password): if username in users: print("Username already exists") else: users[username] = password print("Account created") def login(username, password): if username not in users: print("Username not found") elif users[username] == password: print("Login successful") else: print("Password incorrect")
This code does three things: it creates an empty dictionary called users, defines a function to add new accounts, and defines a function to check login attempts. To test it, add these lines at the bottom of the file:
create_account("alice", "mypassword123") login("alice", "mypassword123") login("alice", "wrongpassword")
Run the file by typing python login_system.py in your terminal. You should see "Account created", "Login successful", and "Password incorrect" printed in order. This version works, but it stores passwords in plain text — anyone who reads your code or data file sees the actual passwords.
Why plain text passwords are dangerous
If someone gains access to your code or the file where you store usernames and passwords, they can read every password when ready. They do not have to guess or crack anything. This is why real systems never store passwords as plain text, even if the system is small or private.
The solution is hashing — a one-way conversion that turns a password into a long string of characters that cannot be reversed. When a user creates an account, you hash their password and store the hash. When they log in, you hash what they typed and compare the two hashes. If the hashes match, the password is correct. If someone steals your data, they see only the hashes, not the actual passwords.
Python includes a library called hashlib that does this. It is built in, so you do not have to read anything.
Adding password hashing with hashlib
Replace your login_system.py file with this version:
import hashlib import os users = {} def hash_password(password): return hashlib.sha256(password.encode()).hexdigest() def create_account(username, password): if username in users: print("Username already exists") else: hashed = hash_password(password) users[username] = hashed print("Account created") def login(username, password): if username not in users: print("Username not found") else: hashed = hash_password(password) if users[username] == hashed: print("Login successful") else: print("Password incorrect")
The new hash_password function takes a password, converts it to bytes with .encode(), runs it through SHA-256 (a hashing algorithm), and returns the result as a readable string with .hexdigest(). The create_account function now hashes the password before storing it. The login function hashes what the user typed and compares it to the stored hash.
Test it with the same code as before:
create_account("alice", "mypassword123") login("alice", "mypassword123") login("alice", "wrongpassword")
Run it and you will see the same output, but now the password is stored as a hash. If you print users after creating an account, you will see a long string of characters instead of the actual password.
Storing accounts in a file so they persist
Right now, your accounts disappear when the program stops. To keep them, save the dictionary to a file. Python's json library makes this straightforward. Add these lines to the top of your file, after the imports:
import json DATA_FILE = "users.json" def load_users(): try: with open(DATA_FILE, "r") as f: return json.load(f) except FileNotFoundError: return {} def save_users(): with open(DATA_FILE, "w") as f: json.dump(users, f) users = load_users()
The load_users function opens the file users.json and reads the stored dictionary. If the file does not exist yet, it returns an empty dictionary. The save_users function writes the current dictionary to the file. Replace the line users = {} with users = load_users() so the program loads saved accounts when it starts.
Now, after every successful account creation or login attempt, call save_users() to write the changes to disk. Modify create_account like this:
def create_account(username, password): if username in users: print("Username already exists") else: hashed = hash_password(password) users[username] = hashed save_users() print("Account created")
Run the program, create an account, and stop it. When you run it again and try to log in with the same username and password, it will work — your account was saved.
Adding a loop so users can try multiple times
Right now the program runs once and stops. Add a menu so users can create accounts, log in, or quit without restarting:
def main(): while True: print("\n1. Create account") print("2. Login") print("3. Quit") choice = input("Choose an option: ") if choice == "1": username = input("Enter username: ") password = input("Enter password: ") create_account(username, password) elif choice == "2": username = input("Enter username: ") password = input("Enter password: ") login(username, password) elif choice == "3": print("Goodbye") break if __name__ == "__main__": main()
Add this to the bottom of your file, replacing any test code you had. The while True loop keeps running until the user chooses to quit. The if __name__ == "__main__" line ensures the menu only runs when you execute the file directly, not if another program imports it.
Common mistakes and how to fix them
One frequent error is forgetting to call save_users() after creating an account. The account appears to work, but when you restart the program, it is gone. Add the save call to every function that changes the users dictionary.
Another mistake is comparing passwords directly instead of hashing them first. If you write if password == users[username], you are comparing plain text to a hash, which will never match. Always hash the input before comparing.
A third issue is not handling the case where a username does not exist. If you try to access users[username] when the username is not in the dictionary, Python will crash with a KeyError. Check if username in users first, as shown in the code above.
Finally, remember that hashing is one-way. You cannot recover the original password from a hash. If a user forgets their password, you cannot show it to them — you would have to let them set a new one.
Frequently Asked Questions
Is SHA-256 the best hashing method for passwords?
SHA-256 is better than storing plain text, but it is not the best choice for passwords. Libraries like bcrypt and argon2 are designed specifically for passwords and are harder to crack. For a learning project, SHA-256 works fine. For real systems, use bcrypt.
What if someone types the username wrong — should I tell them?
Telling users whether a username exists or not is a security risk. An attacker can use this to find out which usernames are registered. Instead, show the same message for both wrong usernames and wrong passwords: "Username or password incorrect."
Can I see what password a user set?
No, and that is the point. Once you hash a password, you cannot reverse it to see the original. If you need to check a password, you hash what the user typed and compare the hashes. This protects users even if someone steals your data file.
How do I let users change their password?
Write a function that asks for the current password, verifies it by hashing and comparing, then asks for a new password. Hash the new password and store it. This way, users prove they know the old password before changing it.
What happens if the users.json file gets corrupted?
The json.load() function will crash. To handle this, wrap it in a try-except block like the load_users() function already does. You can also add a check: if the file exists but is not valid JSON, print a warning and start with an empty dictionary.