Tech With Galvan
Back to Articles
Development11/1/2024 • 3 min read

Password Generator using Python and Streamlit

Build a secure password generator in Python and Streamlit using the secrets module — custom length, character classes, and entropy scores.

Galvan
Galvan

Founder & Creator

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

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 of random.choice() for cryptographically secure output.
  • Add a copy to clipboard button.
  • Let users exclude ambiguous characters like 0, O, l, and 1.

Common Errors & Fixes

  • TypeError: 'str' object cannot be interpreted as an integer — you passed a string to secrets.choice range logic; secrets.choice takes 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.code or 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.