Passwords¶
4 endpoints for the full password lifecycle — from hashing at registration to strength feedback at input time.
| Method | Endpoint | Purpose |
|---|---|---|
POST |
/v1/auth/hash-password |
Hash a password with bcrypt, argon2, or scrypt |
POST |
/v1/auth/verify-password |
Verify a password against a stored hash |
POST |
/v1/auth/password-strength |
Analyse password strength with crack-time estimate |
GET |
/v1/auth/generate-password |
Generate cryptographically secure random passwords |
Python SDK Examples¶
Hash a password at registration¶
hash_password supports three modern algorithms. Argon2id is the recommended default — it was the winner of the Password Hashing Competition and is resistant to both GPU and side-channel attacks.
from toolkitapi import Auth
auth = Auth(api_key="tk_...")
# Argon2id — recommended default
result = auth.hash_password("hunter2", algorithm="argon2")
print(result["hash"])
# $argon2id$v=19$m=65536,t=3,p=4$...
# bcrypt — widely supported, cost factor 12 is the modern baseline
bcrypt_result = auth.hash_password("hunter2", algorithm="bcrypt", rounds=12)
print(bcrypt_result["hash"])
# $2b$12$...
# scrypt — log2(N) work factor
scrypt_result = auth.hash_password("hunter2", algorithm="scrypt", rounds=14)
print(scrypt_result["hash"])
# $scrypt$ln=14,r=8,p=1$...
Full registration flow¶
from toolkitapi import Auth
auth = Auth(api_key="tk_...")
def register_user(username: str, plaintext_password: str) -> dict:
"""Hash the password and return the user record to store."""
result = auth.hash_password(plaintext_password, algorithm="argon2")
return {
"username": username,
"password_hash": result["hash"],
"hash_algorithm": result["algorithm"],
}
user = register_user("alice", "correct horse battery staple")
# Store user["password_hash"] in your database — never the plaintext
Verify a password at login¶
verify_password automatically detects the algorithm from the hash prefix — no need to store or pass the algorithm separately.
from toolkitapi import Auth
auth = Auth(api_key="tk_...")
stored_hash = "$argon2id$v=19$m=65536,t=3,p=4$..."
result = auth.verify_password("hunter2", stored_hash)
print(result["valid"]) # True or False
print(result["needs_rehash"]) # True if parameters are below current recommendations
Full login flow with rehash detection¶
When needs_rehash is True the stored hash used a lower cost factor than the current recommendation. Upgrade it transparently during a successful login (when you still have the plaintext).
from toolkitapi import Auth
auth = Auth(api_key="tk_...")
def verify_login(
plaintext: str,
stored_hash: str,
update_hash_callback,
) -> bool:
"""Verify login and silently upgrade the hash if needed."""
result = auth.verify_password(plaintext, stored_hash)
if not result["valid"]:
return False
if result["needs_rehash"]:
# Re-hash with current parameters and persist the new hash
new_result = auth.hash_password(plaintext, algorithm="argon2")
update_hash_callback(new_result["hash"])
return True
Analyse password strength¶
password_strength uses the zxcvbn library — it models real attacker patterns (dictionary words, common substitutions, keyboard patterns, dates) rather than simple character-class rules.
from toolkitapi import Auth
auth = Auth(api_key="tk_...")
passwords = [
"password",
"p@ssw0rd",
"correct horse battery staple",
"Tr0ub4dor&3",
"Xk#9mQ!2vLpR",
]
for pw in passwords:
result = auth.password_strength(pw)
score = result["score"] # 0 (very weak) to 4 (very strong)
crack = result["crack_time_display"]
print(f"{pw:30} score={score} crack={crack}")
for suggestion in result["feedback"]["suggestions"]:
print(f" → {suggestion}")
Output:
password score=0 crack=less than a second
→ Add another word or two. Uncommon words are better.
→ Use a few words, avoid common phrases
p@ssw0rd score=0 crack=less than a second
→ Predictable substitutions like '@' instead of 'a' don't help very much
correct horse battery staple score=3 crack=centuries
Tr0ub4dor&3 score=2 crack=months
Xk#9mQ!2vLpR score=4 crack=centuries
Real-time strength indicator¶
from toolkitapi import Auth
auth = Auth(api_key="tk_...")
STRENGTH_LABELS = {0: "Very Weak", 1: "Weak", 2: "Fair", 3: "Strong", 4: "Very Strong"}
MIN_SCORE = 2 # Require "Fair" or better
def check_password_policy(password: str) -> tuple[bool, str, list[str]]:
"""Return (passes_policy, strength_label, suggestions)."""
result = auth.password_strength(password)
score = result["score"]
label = STRENGTH_LABELS[score]
suggestions = result["feedback"]["suggestions"]
warnings = result["feedback"]["warnings"]
if warnings:
suggestions = warnings + suggestions
return score >= MIN_SCORE, label, suggestions
Generate secure random passwords¶
generate_password uses Python's secrets module for cryptographically secure randomness. All character set and length options are applied server-side before the entropy calculation.
from toolkitapi import Auth
auth = Auth(api_key="tk_...")
# Single password — defaults: 20 chars, all character sets
result = auth.generate_password()
print(result["passwords"][0]) # e.g. "Kx#9mQ!2vLpR$Tn7wBqZ"
print(result["entropy_bits"]) # e.g. 131.1
# Batch of 10 — system-generated temporary passwords
batch = auth.generate_password(count=10, length=16, symbols=False)
for pw in batch["passwords"]:
print(pw)
# Human-readable — no ambiguous characters (0/O/1/l/I)
readable = auth.generate_password(
length=24,
exclude_ambiguous=True,
)
print(readable["passwords"][0])
Generate passwords for a bulk user import¶
from toolkitapi import Auth
auth = Auth(api_key="tk_...")
def provision_temp_passwords(user_count: int) -> list[str]:
"""Generate one temporary password per user, up to 50 at a time."""
passwords = []
for batch_start in range(0, user_count, 50):
batch_size = min(50, user_count - batch_start)
result = auth.generate_password(
count=batch_size,
length=20,
exclude_ambiguous=True,
)
passwords.extend(result["passwords"])
return passwords
Response Fields¶
hash-password response:
| Field | Type | Description |
|---|---|---|
hash |
string | Hashed password string |
algorithm |
string | Algorithm used: bcrypt, argon2, or scrypt |
parameters |
object | Algorithm-specific cost parameters |
verify-password response:
| Field | Type | Description |
|---|---|---|
valid |
bool | Whether the password matches the hash |
algorithm_detected |
string | Algorithm detected from the hash format |
needs_rehash |
bool | true if parameters are below current recommendations |
password-strength response:
| Field | Type | Description |
|---|---|---|
score |
int | 0 (very weak) – 4 (very strong) |
crack_time_display |
string | Human-readable offline crack time estimate |
entropy_bits |
float | Estimated entropy in bits |
feedback.warnings |
list | Specific warnings about the password |
feedback.suggestions |
list | Suggestions to improve strength |
generate-password response:
| Field | Type | Description |
|---|---|---|
passwords |
list | Generated password strings |
entropy_bits |
float | Bits of entropy per password |
Tip
For new user registrations, run password_strength before hash_password so you can reject weak passwords before hashing. The score field maps directly to a UI strength bar: 0–1 = reject, 2 = warn, 3–4 = accept. Only hash passwords that pass your minimum strength threshold.