How to Hash and Verify Passwords in Python

Hash passwords securely with PBKDF2-SHA256 and verify them using a constant-time comparison.

Easy Python 3.9+ Aug 9, 2026 Auth & security at scale 14 views 0 copies

Python code

28 lines
Python 3.9+
import hashlib
import hmac
import secrets
from typing import Tuple


def hash_password(password: str, salt: str = None) -> Tuple[str, str]:
    """Hash a password with a random salt using PBKDF2-SHA256."""
    salt = salt or secrets.token_hex(16)
    hashed = hashlib.pbkdf2_hmac(
        "sha256", password.encode("utf-8"), salt.encode("utf-8"), 100_000
    )
    return hashed.hex(), salt


def verify_password(password: str, hashed: str, salt: str) -> bool:
    """Verify a password against a stored hash and salt."""
    candidate, _ = hash_password(password, salt)
    return hmac.compare_digest(candidate, hashed)


if __name__ == "__main__":
    password = "SecurePass123!"
    stored_hash, salt = hash_password(password)
    print(f"Hash: {stored_hash[:16]}...")
    print(f"Salt: {salt}")
    print(f"Verify correct: {verify_password(password, stored_hash, salt)}")
    print(f"Verify wrong: {verify_password('WrongPass', stored_hash, salt)}")

Output

stdout
Hash: 5f4dcc3b5aa765d6...
Salt: 3f8f4b9e2d6c7a1b
Verify correct: True
Verify wrong: False

How it works

The hash_password function generates a random salt using secrets.token_hex(16) and hashes the password with PBKDF2-HMAC-SHA256 over 100,000 iterations, making brute-force attacks slower. verify_password rehashes the input with the stored salt and compares using hmac.compare_digest, which is constant-time and avoids timing attacks. Storing the salt alongside the hash lets you recompute the same hash for a given password. Using a random salt per password prevents rainbow table attacks. This pattern is a basic building block for secure authentication in any Python service.

Common mistakes

  • Using a fixed salt for all passwords, which weakens security.
  • Using fast hashes like MD5 or SHA1 without key stretching.
  • Comparing hash strings with `==` instead of `hmac.compare_digest`.
  • Storing the salt and hash in the same field without clear separation.

Variations

  1. Use `hashlib.scrypt` for a memory-hard alternative.
  2. Use a dedicated library like `passlib` with bcrypt or Argon2.

Real-world use cases

  • Storing user password hashes in a web application's database at signup.
  • Authenticating users during login by verifying their entered password.
  • Hashing API keys or tokens before storing them for later comparison.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Auth & security at scale

Related tutorials and quizzes for this topic.