"""One-time tokens for invitation and password-reset links. Only a SHA-256 hash is stored, so a database leak does not expose usable links. The raw token exists only in the link shown to the admin once. """ import hashlib import secrets def new_token(): """Return (raw_token, token_hash).""" raw = secrets.token_urlsafe(32) return raw, hash_token(raw) def hash_token(raw): return hashlib.sha256(raw.encode()).hexdigest()