Courses/Streamlit: 20 Real Apps/Module 3: Beginner Projects
Module 3 · Lesson 420 minBeginner

Project 4: Password Generator

What you'll build
Build a cryptographically secure password generator with entropy scoring.

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:
  • code
    pip install streamlit

    Step 1: Create the Script

    Create password_generator.py and paste the following:

    code
    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

    code
    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 EnabledStrength
    1Weak
    2Fair
    3Good
    4Strong

    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.

    Adapted from: Password Generator using Python and Streamlit

    Checkpoint
    Generated passwords match your chosen length and character classes, every time.
    What you learned
    • The secrets module vs random
    • Guaranteed-diversity generation + shuffle
    • Entropy as a strength measure