os.urandom
The OS cryptographic random source as bytes: /dev/urandom or the getrandom() syscall on Linux, BCryptGenRandom() on Windows. Available everywhere; os.getrandom() and its GRND_* flags are Linux only (Linux 3.17+). For tokens and passwords use the secrets module, which is built on the same source.
Common call
os.urandom(16)
Returns
bytes of length 16, different on every call
Replaces
random.getrandbits / random.randbytes for anything secret
Watch out
It returns bytes, not text: use .hex() or secrets.token_hex()
os.urandom(sizesize — Number of bytes. 0 gives b"", a negative size raises ValueError.type: int · required, /)
→ bytes
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| size | int | yes | Number of bytes. 0 gives b"", a negative size raises ValueError. |
| flags | int | no (0) | os.getrandom() only: GRND_NONBLOCK (raise BlockingIOError instead of blocking) and/or GRND_RANDOM (read from the /dev/random pool), OR-ed together. |
Return value
bytes — Exactly size bytes from the OS randomness source.
Common patterns
A random key or salt
Bytes straight from the OS, the input that hashlib.pbkdf2_hmac and friends expect.
import hashlib, os salt = os.urandom(16) key = hashlib.pbkdf2_hmac('sha256', b'password', salt, 600_000)
Text tokens with secrets
secrets turns the same OS randomness into hex or URL-safe text.
import secrets reset_token = secrets.token_urlsafe(32) api_key = secrets.token_hex(20)
Non-blocking read on Linux
GRND_NONBLOCK makes getrandom raise BlockingIOError instead of waiting for the entropy pool at early boot.
import os try: seed = os.getrandom(32, os.GRND_NONBLOCK) except BlockingIOError: seed = None # pool not initialised yet
Examples
1. bytes of the requested length
import os
b = os.urandom(16)
(type(b).__name__, len(b))
Returns
('bytes', 16)2. Zero bytes is allowed
import os
os.urandom(0)
Returns
b''3. Two calls differ
import os
os.urandom(8) == os.urandom(8)
Returns
False4. As an unsigned integer
import os
int.from_bytes(os.urandom(4), 'big') < 2**32
Returns
True5. secrets: 16 bytes as 32 hex characters
import secrets
len(secrets.token_hex(16))
Returns
326. secrets: URL-safe text token
import secrets
t = secrets.token_urlsafe(32)
(type(t).__name__, len(t))
Returns
('str', 43)7. Negative size
import os
os.urandom(-1)
Returns
ValueError: negative argument not allowedPitfalls
1. Using the random module for secrets
random is a seeded Mersenne Twister: anyone who learns or guesses the seed reproduces every value. Tokens, salts and keys must come from os.urandom / secrets.
random.Random
import random random.Random(1).randbytes(8) == random.Random(1).randbytes(8)
True
secrets / os.urandom
import secrets secrets.token_bytes(8) == secrets.token_bytes(8)
False
2. Turning the bytes into text with str()
str() of bytes gives the repr with b and escapes, not a usable token. Encode with .hex() or base64, or use secrets.token_hex directly.
str(bytes)
str(b'\x00\xff')
"b'\\x00\\xff'"
.hex()
b'\x00\xff'.hex()
'00ff'
3. Passing a float size
size must be an int; compute it with // or int() first.
bits / 8
import os os.urandom(20 / 8)
TypeError: 'float' object cannot be interpreted as an integer
bits // 8
import os len(os.urandom(256 // 8))
32
When to use
Use it
- Keys, salts, nonces and IVs for cryptographic code
- Seeding your own generator from a source nobody can predict
Reach for something else
- Text tokens, passwords, choices from an alphabet → secrets.token_urlsafe / token_hex / secrets.choice
- Reproducible simulations and tests → random.Random(seed)
- Random numbers in a range → secrets.randbelow or random.SystemRandom
Notes
CPython impl
Linux: getrandom() syscall in blocking mode (waits only until the kernel entropy pool is initialised, PEP 524); other Unix: /dev/urandom (NotImplementedError if it is missing); Windows: BCryptGenRandom() since 3.11
Availability
urandom: Unix, Windows. getrandom and GRND_NONBLOCK / GRND_RANDOM: Linux 3.17+ only, added in 3.6 (on Linux GRND_NONBLOCK == 1 and GRND_RANDOM == 2)
getrandom
May return fewer bytes than requested; with GRND_NONBLOCK it raises BlockingIOError instead of blocking. Reading large amounts drains the pool other users share, so prefer urandom
secrets
secrets.token_bytes / token_hex / token_urlsafe / randbelow / choice and random.SystemRandom all draw from os.urandom
FAQ
Yes. It reads the operating system CSPRNG (getrandom()/dev/urandom on Linux, BCryptGenRandom on Windows), which is what the docs describe as suitable for cryptographic use. The examples on this page only check lengths and types because the bytes are different on every run.