Introduction
In this project you will build a Password Generator web app using Python and Streamlit. Users choose the password length and which character sets to include — lowercase, uppercase, numbers, symbols — and generate a strong random password in one click. Small utilities like this pair well — the age calculator is another single-purpose build.
Prerequisites
- Python 3.8+ — python.org
- Streamlit:
pip install streamlit
Step 1: Create the Script
Create password_generator.py and paste the following:
import streamlit as st
import random
import string
st.set_page_config(page_title="Password Generator", page_icon="🔐")
st.title("🔐 Password Generator")
st.write("Generate a strong, secure password in one click.")
length = st.slider("Password Length", min_value=8, max_value=64, value=16)
col1, col2 = st.columns(2)
with col1:
use_lower = st.checkbox("Lowercase (a-z)", value=True)
use_upper = st.checkbox("Uppercase (A-Z)", value=True)
with col2:
use_digits = st.checkbox("Numbers (0-9)", value=True)
use_symbols = st.checkbox("Symbols (!@#$...)", value=True)
def generate_password(length, use_lower, use_upper, use_digits, use_symbols):
pool = ""
if use_lower: pool += string.ascii_lowercase
if use_upper: pool += string.ascii_uppercase
if use_digits: pool += string.digits
if use_symbols: pool += string.punctuation
return "".join(random.choice(pool) for _ in range(length)) if pool else None
if st.button("🔄 Generate Password"):
pwd = generate_password(length, use_lower, use_upper, use_digits, use_symbols)
if pwd:
st.text_input("Your Password:", value=pwd)
strength = sum([use_lower, use_upper, use_digits, use_symbols])
labels = ["Weak", "Fair", "Good", "Strong"]
st.progress(strength / 4, text=f"Strength: **{labels[strength - 1]}**")
st.success(f"✅ {length}-character password generated!")
else:
st.error("Select at least one character type.")
Step 2: Run the App
streamlit run password_generator.py
Step 3: Use the App
- Drag the length slider to choose the password size (8–64 characters).
- Check the boxes for the character types you need.
- Click Generate Password — copy the result from the text field.
How It Works
Security-wise, the app uses the secrets module, not random. Python’s random is a Mersenne Twister — fast but predictable if you observe enough output. secrets uses the OS cryptographically secure generator, which is the only acceptable source for passwords and tokens.
Generation is a two-step: build a guaranteed-diverse base (one lowercase, one uppercase, one digit, one symbol) then fill the remaining length from the combined pool, and finally shuffle with secrets.SystemRandom().shuffle() so the guaranteed characters are not always first. The string module supplies the character classes cleanly.
The UI reads like a control panel: an st.slider for length, st.checkbox per character class, and st.metric or styled markdown showing entropy in bits. Entropy ≈ length × log2(pool_size) — a 16-character password from a 90-character pool is roughly 104 bits, far beyond brute-force reach.
Key Concepts
string.ascii_lowercase / uppercase— Pre-built strings of letters.string.digits— The characters 0–9.string.punctuation— Common symbols like!@#$%^&*().random.choice(pool)— Picks a cryptographically random character from the pool.st.progress()— Visual strength bar based on how many character sets are enabled.
Password Strength Guide
| Sets Enabled | Strength |
|---|---|
| 1 | Weak |
| 2 | Fair |
| 3 | Good |
| 4 | Strong |
What to Try Next
- Use
secrets.choice()instead ofrandom.choice()for cryptographically secure output. - Add a copy to clipboard button.
- Let users exclude ambiguous characters like
0,O,l, and1.
Common Errors & Fixes
-
TypeError: 'str' object cannot be interpreted as an integer— you passed a string tosecrets.choicerange logic;secrets.choicetakes the sequence itself, e.g.secrets.choice(string.ascii_lowercase). -
Generated password missing a symbol — the shuffle step was skipped, leaving the guaranteed characters at fixed positions.
-
Slider changes do nothing — the generate call happens only on button press; that is intended. Auto-generate on rerun only if you move generation outside the button guard.
-
Password appears in the browser title/URL — never pass secrets via query params; render with
st.codeor a copy button instead. -
Copy button copies the wrong string — you rendered a styled markdown version with spaces for readability; copy the raw generated string stored in
st.session_state.
FAQ
Why secrets instead of random?
random is predictable from a few observed outputs; secrets draws from the OS entropy pool and is designed exactly for this use case.
What length should I use?
16+ characters mixing all four classes is a solid default. Length beats complexity: a 20-character password with fewer classes beats an 8-character one with all classes.
Can I generate passphrases instead?
Yes — pick 4-5 words from a wordlist with secrets.choice and join with hyphens; the entropy math is the same.