Python 3.6 introduced a secrets module for generating robust and secure random numbers. In this lesson, you’ll learn how to use secrets.SystemRandom()
class and secrets module functions to create random numbers, data, URLs, and tokens securely and safely.
Table of contents
Why use the secrets module
The cryptographically secure random generator generates random data using synchronization methods to ensure that no two processes can obtain the same data simultaneously.

The random generator provided by the Python random module is a pseudo-random number generator that is not cryptographically secure. As a result secrets module is added in Python 3.6 and onwards to secure the random number generator.
Before Python 3.6, we have the random() and SystemRandom class to cryptographically secure random generator.
The secrets module is CSPRNG, i.e., cryptographically strong Pseudo-Random Number Generator. It is used to produce random numbers that are secure and useful in security-sensitive applications. The PEP – 0506 is designed to add the secrets module to the Python standard library.
Use the secrets module for following standard security-related functions.
- Generating random numbers,
- Creating passwords and OTP.
- Random token.
- Password recovery safe URLs and session keys.
Note: The secrets module available only in Python 3.6 and above. If you are using an older version of Python, please refer to How to secure a random generator in Python.
The secrets module is based on os.urandom()
and random.SystemRandom()
, an the interface to the operating system’s best source of cryptographic randomness.
- On windows,
os.urandom()
internally uses CryptGenRandom(). - Linux 3.17 and newer, the
getrandom()
syscall used when available. - On OpenBSD 5.6 and newer, the C
getentropy()
function is used.
Let see how to use the secrets module.
Class secrets.SystemRandom
- A class for generating secure random numbers using the highest-quality sources provided by the operating system.
- Using the
secrets.SystemRandom
class, we can use all the functions of a random module. - Before the secrets module, we were using
random.SystemRandom
class to cryptographically secure random data. The same class is also accessible using the secrets module. Just execute thesecrets.SystemRandom()
, and it will return the instance of a secure random generator
Let see the example of how to use secrets.SystemRandom
class to secure the random generator.
import secrets
# Getting systemRandom class instance out of secrets module
secretsGenerator = secrets.SystemRandom()
# secure random integer numbers
random_number = secretsGenerator.randint(0, 50)
print(random_number)
# Output 38
# secure random integer number within given
random_number2 = secretsGenerator.randrange(4, 40, 4)
print(random_number2)
# Output 32
# Secure Random choice using secrets
number_list = [6, 12, 18, 24, 30, 36, 42, 48, 54, 60]
secure_choice = secretsGenerator.choice(number_list)
print(secure_choice)
# Output 60
# Secure Random sample
secure_sample = secretsGenerator.sample(number_list, 3)
print(secure_sample)
# output [12, 42, 48]
# Secure Random float number
secure_float = secretsGenerator.uniform(2.5, 25.5)
print(secure_float)
# Output 18.062235454990407
Secrets Module Functions
Let see how to use secrets module functions.
Function | Description |
---|---|
secrets.SystemRandom() | Get an instance of the secure random generator |
secrets.randbelow(n) | Generate a secure random integer number |
secrets.choice(seq) | Returns a secure random element from a non-empty sequence |
secrets.randbits(k) | returns a secure unsigned integer with k random bits |
secrets.token_bytes([nbytes=None]) | Return a secure random byte string |
secrets.token_hex([nbytes=None]) | Return a secure random text string, in hexadecimal format |
secrets.token_urlsafe([nbytes=None]) | Return a secure random URL-safe text string |
secrets.compare_digest(a, b) | To reduce the risk of timing attacks |
randbelow(n)
- Use the
secrets.randbelow
function to generate a secure integer number. - This function returns a secure random integer in the range [0, n). Here
n
is the exclusive upper bound. - 0 is the starting number in the range, and
n
is the last number. - For example,
secrets.randbelow(10)
generate a single random number from 0 to 9.
Example:
import secrets
# secure Random integer number
for i in range(3):
print(secrets.randbelow(10), end=', ')
# Output 0, 8, 6,
choice(sequence)
The secrets.choice(sequence)
method returns a secure randomly-chosen element from a non-empty sequence. Here sequence can be list, tuple, or string.
Example:
import secrets
name = "GuidoVanRossum"
# secrets choice from string is
print(secrets.choice(name))
# Output 'm'
name_list = ["Guido Van Rossum", "Bjarne Stroustrup", "Dennis Ritchie"]
# secure choice from list
print(secrets.choice(name_list))
# Output 'Bjarne Stroustrup'
randbits(k)
- This method returns a secure unsigned integer with
k
random bits. - This function is to generate a random bitmask that would contain
N
bits set (this is not the same as generating a random integer since that is not guaranteed to haveN
bits set in it). - A random number generated using
randbits
is more secure.
It generates a random integer within a bit range.
- If
k=4
then Unsigned integer From 0 to 15. k=8
then Unsigned integer From 0 to 255.- If
k=16
then Unsigned integer From 0 to 65,535, and so on.
Let’s see the example :
import secrets
# using 4 bits
print(secrets.randbits(4))
# output 7
# using 8 bits
print(secrets.randbits(8))
# output 73
# using 16 bits
print(secrets.randbits(16))
# Output 509
# using 32 bits
print(secrets.randbits(32))
# Output 2740049514
Generate secure token using secrets module
The secrets module provides functions for generating the secure tokens, useful for applications to generate reset password tokens and hard-to-guess URLs.
Use the following functions to generate a secure token.
secrets.token_bytes([nbytes=None])
: Return a secure random byte string containing the number of bytes. Ifn-bytes
are not supplied, a reasonable default gets used.secrets.token_hex([nbytes=None])
: Return a secure random text string in hexadecimal format. The string hasn-bytes
random bytes, and each byte is converted to two hex digits. If n-bytes are not supplied, a reasonable default gets used.secrets.token_urlsafe([nbytes=None])
: Return a secure random URL-safe text string, containing n-bytes random bytes. Use this method to generate secure hard-to-guess URLs.
Example to generate secure tokens
import secrets
# secure byte token
print(secrets.token_bytes(16))
# secure hexadecimal token
print(secrets.token_hex(32))
# generate secure URLs
passwordResetLink = "demo.com/customer/eric/reset="
passwordResetLink += secrets.token_urlsafe(32)
print(passwordResetLink)
Output:
b'&\x19H\xc0r{\xa5\xd6\x0b\xf5\xb2\x1d\xc6\xf6]0' dd772eb0c11c4995c3c9db5a20a555c31d70547c30df31e818be7c7832bb44f1 demo.com/customer/eric/reset=GzWfp5xCcuFsnEUb9qqN_v94_XOx9hPwSGszdx4rNBk
How many bytes tokens should use
Tokens need to have sufficient randomness To secure against brute-force attacks and timing attacks. As per experts, 32 bytes (256 bits) of randomness is enough to secure against brute-force attacks. You should choose byte size as per your requirement.
Reduce timing attack using compare_digest(a, b)
To reduce the risk of timing attacks secrets module has the compare_digest(a, b)
function. This function returns True
if string a
and b
are equal, otherwise False to reduce the risk of timing attacks.
Practical Example of secrets module
Let see the example now. In this example, we generate a temporary password and send this password on a temporary hard-to-guess URL so the client can reset his password using this URL.
Steps: –
- Generate a ten-character alphanumeric password with at least one lowercase character, at least one uppercase character, at least one digits, and one special symbol.
- Generate a temporary URL
Example:
import secrets
import string
stringSource = string.ascii_letters + string.digits + string.punctuation
password = secrets.choice(string.ascii_lowercase)
password += secrets.choice(string.ascii_uppercase)
password += secrets.choice(string.digits)
password += secrets.choice(string.punctuation)
for i in range(6):
password += secrets.choice(stringSource)
char_list = list(password)
secrets.SystemRandom().shuffle(char_list)
password = ''.join(char_list)
print("Secure Password is ", password)
# Output ^Kk58nL\(A
print("Ppassword Reset URL Link")
SecureURL = "https://demo.com/user/jhon/reset="
SecureURL += secrets.token_urlsafe(32)
print(SecureURL)
# https://demo.com/user/jhon/reset=Td3pRv_USCHfxQsBF0SFejEEFPp1NLaHBkbzth5gRjQ
Next Steps
To practice what you learned in this article, I have created a Python random data generation Exercise and Python random data generation Quiz to test your random data generation concepts.
References: