---
title: "Make tokens from a secure random source · Agent Wranglers"
url: https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/secure-random-tokens
updated: 2026-10-21
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Make tokens from a secure random source

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

For AI agents: [llms.txt](https://agentwranglers.se/llms.txt) is a short guide that sends you to the rules your problem needs, and [rules.json](https://agentwranglers.se/playbook/adversarial-testing/rules.json) holds every rule of this playbook as JSON.

- Level: Recommended
- Chapter: [Access and accounts](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts)
- Rule: Make session IDs, reset codes, API keys and invite links only with the platform's cryptographic random generator. Never use the plain random function, a timestamp or a counter.
- Applies when: The project it has user accounts.
- How: Use `crypto.randomBytes` or `crypto.randomUUID` in Node, the `secrets` module in Python, `random_bytes` in PHP, `SecureRandom` in Java and Ruby, and `crypto/rand` in Go. Plain generators such as `Math.random` are fast but predictable, so an attacker who sees a few values can work out the next. API keys also follow [Store API keys as hashes](https://agentwranglers.se/playbook/api-design/api-security/api-keys). Make each token as long as [Lock down session cookies](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/session-cookies) says. Links in email also follow [single-use and short-lived links](https://agentwranglers.se/playbook/email/email-security/sign-in-links).
- Check: Search the code for `Math.random`, `random.random`, `random.choice`, `mt_rand`, `uniqid` and `math/rand`. No match makes a token, code or ID that grants access.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
import { randomBytes } from 'node:crypto';

// Bad: predictable
const resetCode = Math.random().toString(36).slice(2);
// Good
const resetToken = randomBytes(32).toString('base64url');
```

### Python example

```python
import secrets

# Bad: predictable
reset_code = str(random.randint(100000, 999999))
# Good
reset_token = secrets.token_urlsafe(32)
```

## Sources

- [OWASP Cryptographic Storage Cheat Sheet on secure random numbers](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#secure-random-number-generation)

## Related rules

- [Store API keys as hashes](https://agentwranglers.se/playbook/api-design/api-security/api-keys) in API design
- [Lock down session cookies](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/session-cookies) in Security testing
- [Make sign-in and reset links single-use and short-lived](https://agentwranglers.se/playbook/email/email-security/sign-in-links) in Email

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/secure-random-tokens">Agent Wranglers security testing playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Check every step of single sign-on](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/single-sign-on)
- [Access and accounts](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts)
