For a security-sensitive random token in Python, use the standard-library secrets module rather than the simulation-oriented random module. Generate the value only where it is needed, and avoid printing it into terminal logs, CI output or support tickets. A good random value is one component of a secure workflow, not a complete password-reset or authentication system.
Choose the right kind of randomness
The official Python documentation describes secrets as suitable for passwords, authentication tokens and related secrets. It explicitly prefers this module over the default pseudo-random generator in random for security and cryptography. This distinction matters even if a demonstration using random letters looks unpredictable to a person.
Do not seed a simulation generator with the time, a username or a device identifier and call the result a secure token. Reproducibility is useful in simulations but not a desirable property for an attacker guessing a bearer secret. Also avoid choosing a tiny token space merely because short strings are easier to type.
Specify bytes rather than assuming a character count
secrets.token_hex(nbytes) returns hexadecimal text with two hexadecimal characters for each random byte. secrets.token_urlsafe(nbytes) encodes random bytes as URL-safe text; its argument is still a byte count, not a requested output-character count. The documentation notes that default token entropy can change, so an explicit argument makes a reviewed implementation easier to understand.
The example below requests 32 random bytes. That is a concrete demonstration choice, not a universal security approval for every application or threat model. Review token lifetime, guessing limits and the consequences of compromise with the system owner. Do not take an older dated sizing statement in documentation as a guarantee that one setting fits every future use.
Test properties without printing the secret
Save this as a local disposable Python exercise and run it with Python 3.6 or newer. It generates two values in memory and reports only successful property checks. It does not create accounts, send messages, write token files or contact a service.
import re
import secrets
raw_bytes = 32
hex_token = secrets.token_hex(raw_bytes)
url_token = secrets.token_urlsafe(raw_bytes)
assert len(hex_token) == 2 * raw_bytes
assert re.fullmatch(r'[0-9a-f]+', hex_token)
assert re.fullmatch(r'[A-Za-z0-9_-]+', url_token)
assert secrets.compare_digest(hex_token, hex_token)
assert not secrets.compare_digest(hex_token, hex_token + '0')
print('Token format and comparison checks passed; values not logged.')
The hexadecimal length and allowed-character checks validate the expected representation. They do not prove that a random generator is cryptographically sound. Likewise, a handful of generated values with no collisions would not establish an application’s security. Use the documented security-oriented interface rather than inventing a statistical smoke test as a replacement for it.
The two comparison assertions demonstrate equal and different inputs. compare_digest is provided to reduce timing-attack risks in comparisons; it is not a substitute for request validation, access controls or careful handling of the surrounding application.
Keep generation separate from a production token lifecycle
A production reset-token design also needs an association with the correct account, a defined expiry, invalidation after use and controls against repeated guessing. Those are separate engineering requirements, not features automatically supplied by calling token_urlsafe. This article deliberately does not provide a complete reset endpoint or claim that the short exercise implements one.
Decide how the server will verify a presented value without unnecessarily retaining reusable plaintext secrets. Human-chosen passwords require a password-specific secure storage design; the Python documentation warns against recoverable password storage. Do not casually reuse a token-storage shortcut as password-storage advice.
Review delivery and observability too. A secret embedded in a URL may be captured by systems that record URLs, depending on the application and logging configuration. Avoid copying active tokens into chat, analytics labels or incident screenshots. If a real token is exposed, follow the service’s revocation or replacement procedure; deleting a visible log line does not invalidate the credential.
Use a short review checklist
- Is the value generated by secrets rather than a simulation generator?
- Is the byte count explicit and reviewed for this use?
- Are tests checking format without emitting live values?
- Are expiry, single-use handling and guessing controls implemented elsewhere?
- Can an exposed token actually be invalidated?
Is URL-safe the same as encrypted? No. It describes an encoding appropriate for URL text, not confidentiality. Can I paste the example token into a server configuration? This exercise prints no token and provisions nothing. Use your organisation’s approved secret-generation and delivery workflow for real credentials.
For a related credential-handling distinction, see checking an SSH public-key fingerprint before granting access. Public-key identifiers and private bearer tokens have different disclosure requirements.
Source: Python secrets documentation.
This tutorial is for educational purposes. Test carefully before using code in production. The site owner is not responsible for misuse, damage, data loss or production issues.



