How to make a password in Python
Learn how to create passwords in Python. This guide covers different methods, tips and tricks, real-world applications, and debugging.

A secure password in Python is a key part of development. It protects user data and system integrity. Python’s libraries offer simple tools for this essential security task.
In this article, you'll learn different techniques to generate strong passwords. We'll cover practical tips, real-world applications, and advice to debug common issues, so you can implement secure password functionality.
Basic password generation with random
import random
import string
password = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8))
print(f"Generated password: {password}")--OUTPUT--Generated password: Ks7nR4xP
This method leverages Python's built-in modules for a quick solution. It's a straightforward approach where you first define a pool of characters and then build the password from it. The key steps in the one-liner are:
- Character Pool: The code combines
string.ascii_lettersandstring.digitsto create a source string of all uppercase letters, lowercase letters, and numbers. - Random Selection:
random.choice()is called eight times, picking a random character from the pool for each position in the password. - Assembly: Finally,
''.join()stitches these randomly selected characters together into the final 8-character string.
Basic password techniques
Handling user-created passwords involves new techniques, from securely capturing input with input() and getpass() to verifying password strength.
Getting user input for passwords with input()
password = input("Create a password: ")
confirm_password = input("Confirm your password: ")
if password == confirm_password:
print("Password created successfully!")
else:
print("Passwords don't match!")--OUTPUT--Create a password: MySecret123
Confirm your password: MySecret123
Password created successfully!
The input() function is a basic way to capture text from a user. While simple, it displays the typed characters on the screen, which isn't ideal for sensitive information like passwords. This example demonstrates a common validation pattern.
- The code prompts the user for their password twice to minimize typos.
- It then uses the
==operator to perform a direct string comparison. - If the two inputs match exactly, the password is confirmed. Otherwise, an error is shown.
Creating a password strength checker
def check_strength(password):
score = 0
if len(password) >= 8: score += 1
if any(c.isupper() for c in password): score += 1
if any(c.isdigit() for c in password): score += 1
if any(c in "!@#$%^&*()-_=+" for c in password): score += 1
return score
password = "P@ssw0rd"
print(f"Password strength (0-4): {check_strength(password)}")--OUTPUT--Password strength (0-4): 4
The check_strength function offers a simple way to score a password's complexity. It's a scoring system that adds a point for each security rule the password meets. The function uses any() with generator expressions to efficiently scan the string for required character types.
- A minimum length of eight characters.
- At least one uppercase letter, checked with
c.isupper(). - At least one digit, found using
c.isdigit(). - At least one special character from the specified list.
The final score, from 0 to 4, provides a quick rating of the password's strength.
Hiding password input with getpass
import getpass
# Password input will be hidden during typing
password = getpass.getpass("Enter your password: ")
print(f"Password saved with length: {len(password)}")--OUTPUT--Enter your password:
Password saved with length: 8
For better security, the getpass module is a significant step up from input(). The getpass.getpass() function prompts for user input but keeps the characters hidden as they're typed. It's a simple but crucial security feature for any command-line application that handles sensitive data.
- This prevents "shoulder surfing"—where someone could watch you type your password.
- It works just like
input(), returning the entered string once you press Enter.
The example confirms the input was received by printing its length, avoiding any exposure of the actual password.
Advanced password operations
While basic techniques are a good start, truly secure applications demand more robust methods for generating, storing, and enforcing complex password policies.
Using the secrets module for cryptographically strong passwords
import secrets
import string
alphabet = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(alphabet) for _ in range(12))
print(f"Secure password: {password}")--OUTPUT--Secure password: K7%j9!Ux&2fP
The secrets module is a major upgrade for password generation. Unlike the random module, it's specifically designed for cryptographic use, ensuring the randomness is unpredictable enough for security tasks. This code generates a 12-character password using a more robust method.
- The function
secrets.choice()provides a more secure alternative torandom.choice()for generating passwords. - The character pool is expanded to include special characters with
string.punctuation, increasing complexity. - A longer, 12-character password makes it significantly harder to guess or crack through brute-force attacks.
Securely hashing passwords with hashlib
import hashlib
password = "MySecretPassword"
hashed_password = hashlib.sha256(password.encode()).hexdigest()
print(f"Original: {password}\nHashed: {hashed_password}")--OUTPUT--Original: MySecretPassword
Hashed: 6d040e1a7ca65cfba9a9bd19f03f1e2788a3a25e860e949ef7e780a20a530711
Storing passwords in plain text is a major security flaw. Instead, you should store a hash—a fixed-length, irreversible representation of the password. Python's hashlib module is the standard tool for this job. It turns a password into a unique digital fingerprint that can't be reversed.
- The password string must first be converted into bytes using
password.encode(), as hashing functions operate on bytes, not text. hashlib.sha256()then applies the secure SHA-256 algorithm to the bytes.- Finally,
hexdigest()converts the resulting hash into a hexadecimal string, which is easy to store in a database.
Implementing a custom password policy with re
import re
def validate_password_policy(password):
if len(password) < 10:
return False
if not re.search(r'[A-Z]', password):
return False
if not re.search(r'[0-9]', password):
return False
if not re.search(r'[!@#$%^&*]', password):
return False
return True
print(validate_password_policy("Weak"))
print(validate_password_policy("Strong@Pass123"))--OUTPUT--False
True
The re module lets you enforce complex password rules using regular expressions. The validate_password_policy function uses re.search() to scan the password for required character types. If a pattern isn't found for any rule, the function immediately returns False, failing the validation.
- The policy requires a minimum length of 10 characters.
- It checks for at least one uppercase letter with
r'[A-Z]'. - It ensures there's a number using
r'[0-9]'. - It verifies a special character like
!or@is present.
This method gives you precise control for creating custom security standards for your application.
Move faster with Replit
Replit is an AI-powered development platform that transforms natural language into working applications. You can describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.
For the password techniques we've explored, Replit Agent can turn them into production-ready tools:
- Build a secure password generator utility that lets users customize length and character types, using the
secretsmodule for cryptographic strength. - Create a password strength dashboard that validates user inputs against a custom policy, providing real-time feedback based on rules you define.
- Deploy a simple user registration API that securely captures passwords, hashes them with
hashlib, and stores them in a database.
Simply describe your app idea. Replit Agent will write the code, test it, and fix issues automatically, turning your concept into a working application right in your browser.
Common errors and challenges
When implementing password features in Python, you might encounter subtle bugs and security risks that require careful handling.
Handling exceptions in password validation
Your password validation functions can fail unexpectedly. For instance, if a function designed to check a string's length receives a None value, it will raise a TypeError and crash. Wrapping your validation logic in a try...except block allows you to catch such errors gracefully and provide clear feedback to the user instead of breaking the program.
Handling string encoding correctly with hashlib
The hashlib module requires bytes, not strings, which is why you must use the .encode() method. If you don't specify an encoding format like UTF-8, Python uses a system-dependent default. This can cause the same password to produce different hashes on different machines, preventing users from logging in.
To avoid this, always explicitly encode your strings before hashing. Using password.encode('utf-8') ensures that your hashing function produces consistent, predictable results everywhere.
Avoiding timing attacks in password verification
A subtle but serious vulnerability is the timing attack. When you compare passwords using the standard == operator, the comparison stops the instant it finds a mismatch. Attackers can measure these tiny differences in execution time to guess a password character by character.
- To prevent this, use a function that performs a constant-time comparison. This means it takes the same amount of time to complete, whether the strings match or not.
- Python's
secretsmodule provides the perfect tool for this:secrets.compare_digest(). Always use it to securely compare password hashes.
Handling exceptions in password validation
Your password validation functions can be brittle. If they receive unexpected input, like a None value instead of a string, your program can crash with an AttributeError. This happens because operations like len() can't run on an empty value. The code below demonstrates this exact scenario.
def check_password_strength(password):
# This will raise an AttributeError if password is None
score = 0
if len(password) >= 8: score += 1
if any(c.isupper() for c in password): score += 1
if any(c.isdigit() for c in password): score += 1
return score
user_password = input("Enter password: ")
print(f"Password strength: {check_password_strength(user_password)}")
This function crashes if the password variable is None because it doesn't verify the input type first. Calling methods on a None value results in an AttributeError. The following code shows how to make this function more resilient.
def check_password_strength(password):
# Proper validation with defensive programming
if not password or not isinstance(password, str):
return 0
score = 0
if len(password) >= 8: score += 1
if any(c.isupper() for c in password): score += 1
if any(c.isdigit() for c in password): score += 1
return score
user_password = input("Enter password: ")
print(f"Password strength: {check_password_strength(user_password)}")
The improved check_password_strength function adds a defensive check at the start. It verifies that the password is not None and is a string using if not password or not isinstance(password, str):. This simple guard prevents an AttributeError if the function receives invalid input.
This is crucial when handling data from external sources like databases or APIs, which might return nothing. It’s a key practice for writing robust, crash-proof code.
Handling string encoding correctly with hashlib
Python's hashlib functions operate on bytes, not strings—a distinction that often trips up developers. Forgetting to encode a string before hashing it is a common mistake that will halt your program with a TypeError. The following code demonstrates this exact issue.
import hashlib
password = "MyPassword123"
# This will cause a TypeError because hashlib requires bytes, not strings
hashed_password = hashlib.sha256(password).hexdigest()
print(f"Hashed password: {hashed_password}")
The hashlib.sha256() function requires bytes, but it receives a string, causing a TypeError. This happens because hashing algorithms operate on binary data, not text. The following code demonstrates the correct way to prepare the data.
import hashlib
password = "MyPassword123"
# Correct: Encode the string to bytes before hashing
hashed_password = hashlib.sha256(password.encode()).hexdigest()
print(f"Hashed password: {hashed_password}")
The corrected code fixes the `TypeError` by converting the password string into bytes with password.encode(). Hashing functions like hashlib.sha256() are designed to work on binary data, not text, so they can't process strings directly. Encoding the string first provides the function with the correct data type. This is a crucial step whenever you're hashing data in Python, ensuring your security functions work as expected without crashing.
Avoiding timing attacks in password verification
Using the standard == operator to check passwords creates a subtle but dangerous vulnerability. The comparison stops the instant it finds a mismatch, creating tiny time differences that attackers can measure to guess the password. The following code demonstrates this insecure approach.
# Vulnerable to timing attacks - comparison time varies with matching characters
def verify_password(stored_password, provided_password):
if stored_password == provided_password:
return True
return False
result = verify_password("SecretPass123", "SecretPass456")
print(f"Password verified: {result}")
Because the == operator quits early on a mismatch, it leaks timing information. An attacker can use this to slowly piece together the correct password. The next snippet demonstrates a secure alternative.
import hmac
# Secure against timing attacks - constant time comparison
def verify_password(stored_password, provided_password):
return hmac.compare_digest(stored_password, provided_password)
result = verify_password("SecretPass123", "SecretPass456")
print(f"Password verified: {result}")
The corrected code replaces the insecure == operator with hmac.compare_digest(). This function performs a constant-time comparison, so it takes the same amount of time to execute whether the passwords match or not. This prevents attackers from measuring tiny time differences to guess the password character by character. Always use hmac.compare_digest() when verifying passwords or other secret strings to protect against timing attacks, especially in web applications or APIs.
Real-world applications
With a firm handle on the techniques and potential pitfalls, you can build practical tools like memorable password generators and breach checkers.
Creating memorable password generators with random
Using random.choice(), you can build memorable passphrases by pulling words from predefined lists and adding numbers for extra complexity.
import random
def generate_memorable_password():
adjectives = ["happy", "sunny", "clever", "brave", "mighty", "gentle"]
nouns = ["tiger", "mountain", "river", "forest", "castle", "dragon"]
numbers = random.randint(10, 99)
return f"{random.choice(adjectives)}{random.choice(nouns)}{numbers}"
for _ in range(3):
print(generate_memorable_password())
The generate_memorable_password function creates a human-readable passphrase by combining simple words with a number. It’s a straightforward process that relies on Python's random module to assemble the final string.
- First, it picks one word from the
adjectiveslist and one from thenounslist usingrandom.choice(). - Next,
random.randint()generates a two-digit number for added complexity. - Finally, an f-string assembles these parts into a single, memorable password.
Checking for compromised passwords
A simple but effective security measure is to check if a user's chosen password is on a list of commonly used and easily guessed passwords.
def is_compromised(password):
common_passwords = ["123456", "password", "qwerty", "admin", "welcome",
"password123", "abc123", "letmein", "monkey", "1234567890"]
return password.lower() in common_passwords
# Check common passwords
print(f"Is 'password123' compromised: {is_compromised('password123')}")
print(f"Is 'Unique$tr0ngP@ss' compromised: {is_compromised('Unique$tr0ngP@ss')}")
The is_compromised function determines if a password is too simple by checking it against a hardcoded blocklist. Its logic is efficient and direct, relying on two key steps:
- It first calls
password.lower()to make the comparison case-insensitive. This prevents users from bypassing the check with simple capitalization, like using "Password" instead of "password". - The
inoperator then performs a quick lookup to see if the normalized password exists in thecommon_passwordslist, returningTrueif a match is found.
Get started with Replit
Put these concepts into practice by building a real tool. Just tell Replit Agent what you want, like “a tool that generates memorable passphrases from wordlists” or “a password strength checker API that returns a score.”
The agent writes the code, tests for errors, and deploys your application right in your browser. Start building with Replit.
Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.
Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.


.png)
.png)