The guide
A backup code is only as strong as the service counting the wrong guesses
Backup codes are the spare key of two-step sign-in. Their strength comes from honest randomness, an unbiased alphabet, a service that limits guesses, and a sheet of paper kept in a sensible place.
- 19.93 bits six decimal digits, the least NIST allows for a look-up secret
- 64 bits random content NIST requires in a saved recovery code
- 100 tries most consecutive failed attempts before NIST has the code set disabled
- 1 in 1,000 chance of 100 guesses hitting one of ten unused six-digit codes
- 14.29 percent how much likelier four symbols become when 36 are mapped with modulo
Read the full guide Fold the guide
A second step at sign-in protects an account until the day the second step is gone. Phones are dropped in rivers, replaced, stolen and left in taxis, and the account they guarded does not care about the reason. Backup codes exist for that day. They are a short list of secrets issued in advance, each good for one sign-in, meant to be kept somewhere that does not share the fate of the phone.
The United States standards body NIST has a plain name for them: look-up secrets. Its digital identity guideline describes a physical or electronic record holding a set of secrets shared between a person and a service, and names saved recovery codes as the typical use. It files them under something you have, beside hardware tokens, and adds a caution worth remembering: look-up secrets are not phishing-resistant. Typed into a convincing fake page, a backup code is as lost as a password.
A secret that two parties must share
A backup code has no power of its own. It works because a service wrote it down first and later compares what you type with its record. A code no service has registered is only a string of characters.
So no outside tool can recover or recreate the backup codes of an account that already exists. They live at the service that issued them, and the only way to obtain them is through that account’s own security settings, usually by asking for a fresh set. A generator is useful to the other party: someone building or running a service that needs to hand out codes, or someone whose service lets them supply their own.
For that party the guideline is specific. The list must come from an approved random bit generator. Each secret must be at least six decimal digits or the equivalent. A secret may be used successfully only once. The stored copy must be hashed, and the service must limit failed attempts. Each requirement answers a different attack, and each is easy to get subtly wrong.
Where the randomness comes from
An older Internet document on the subject puts it bluntly: at the heart of all cryptographic systems is the generation of secret, unguessable numbers. It then spends pages on the ways people fool themselves. One is seeding a clever algorithm from the system clock, which leaves an attacker only a few starting values to try. Another is trusting statistics: passing a statistical test does not reveal whether a sequence can be predicted.
That is why a code generator should take its randomness from the operating system and from nowhere else. In a browser the door to it is a single function, specified to fill an array with cryptographically secure random bytes, at most 65,536 of them in one call. The documentation is candid that this is a pseudo-random generator seeded with enough entropy, not a stream of pure physical noise. That design is the normal one.
NIST’s word approved has a formal meaning, though. Its recommendation on deterministic random bit generators specifies particular mechanisms built on hash functions and block ciphers, and a service bound by the guideline is expected to use a generator of that kind. A web page cannot inspect what the browser beneath it uses. A browser tool can honestly say its codes come from the system’s cryptographic generator. It cannot honestly say that the generator has been validated.
The quiet bias of the remainder
Random bytes are not yet codes. A byte has 256 values and an alphabet rarely has a size that divides 256. The tempting shortcut is to take the remainder: byte modulo alphabet size. With 36 symbols, the letters and digits, 256 is seven full rounds of 36 with four values left over. Four symbols are therefore reached by eight byte values and the other thirty-two by seven.
Those four symbols come up 14.29 percent more often than the rest. No single code looks wrong. Across two million symbols, though, a chi-square test of the symbol counts returns a figure near 3,900, where the published table puts the limit for a fair source at about 67. An attacker who knows the generator tries the favoured symbols first.
The cure is rejection sampling. Keep only as many low bits of the byte as the alphabet needs, and if the value still falls outside the alphabet, throw the byte away and draw another. Every symbol is then reached by exactly the same number of byte values, at the price of some discarded bytes. An alphabet of 32 symbols needs no discards at all, because 256 divides evenly, which is one of the quiet attractions of base 32.
The alphabet matters for a second reason: people have to read these codes from paper and type them. Douglas Crockford’s Base 32 uses ten digits and 22 letters, leaving out I and L because they are confused with 1, O because it is confused with 0, and U to avoid accidental obscenity. A decoder accepts lower case and treats the look-alikes as the digits they resemble. Hyphens may be added anywhere for readability, and an optional check symbol, the number modulo 37, catches a mistyped or transposed character before a guess is spent.
How many bits are enough
The strength of a random code is easy to state: its length times the base-two logarithm of the alphabet size. Six digits give 6 times 3.32, or 19.93 bits, about a million possibilities. Sixteen symbols of a 32-symbol alphabet give exactly 80 bits. Ten symbols from a 31-symbol alphabet give 49.54. A check symbol adds nothing, since it is computed from the others.
Twenty bits sounds absurdly small beside the numbers quoted for encryption keys, and the earlier revision of the guideline did set the floor at 20 bits. The reason so little can be enough is that nobody attacks a backup code by computing. They attack it by typing guesses into a live service, and the service is counting.
The current guideline allows at most 100 tries in a row to fail before the authenticator is disabled, and explains the figure with the example of 100 attempts against a six-digit code. Here is the worked example. A set of ten unused six-digit codes covers ten of a million values. One hundred different guesses cover a hundred of them. The chance that the two overlap is very nearly 100 times 10 divided by 1,000,000, or 1 in 1,000. The exact figure, counting guesses without repeats, is a shade lower.
Change one number and the picture moves. Without a limit on guesses, a million possibilities can simply be tried in turn. With sixteen base-32 symbols, a hundred guesses succeed about once in ten to the power 21. The lesson is not that long codes are pointless. It is that short codes are only safe behind a service that counts, and a designer who cannot vouch for the counting should buy margin with length. NIST itself asks for at least 64 bits from the random generator in a saved recovery code.
Length matters again when the database leaks. The guideline wants every look-up secret stored as a hash, and it draws a line at 112 bits. At or above it, one pass of an approved hash is enough, because trying every possible code is out of reach. Below it, the secret must be salted and put through a password hashing scheme with a salt of at least 32 bits, exactly as a password would be.
The classic scheme is PBKDF2, which repeats a keyed hash many times. Its specification notes that an iteration count of c adds about log2(c) bits of work. NIST’s 2010 recommendation suggested a minimum of 1,000 iterations and as many as practical; a widely used open security guide now suggests 600,000 with SHA-256. That figure adds roughly 19 bits, so a six-digit code hashed that way still costs an attacker under 40 bits of effort. Slow hashing delays a thief. It does not turn a short code into a strong one. Anyone implementing it should check their function against the published test vectors before trusting it.
Paper, managers, and the day one is used
Then there is the humble question of where the list lives. NIST says saved recovery codes are intended to be maintained offline, printed or written down, and stored securely. The United Kingdom’s National Cyber Security Centre tells the public much the same: codes are ideal as a fallback because they work even without your phone, each works only once, and you need to store them somewhere safe.
Paper has real virtues. It cannot be reached over a network, it survives a dead battery, and a card cut to the 85.6 by 53.98 millimetre size of a bank card fits a wallet. Its weaknesses are just as physical. NIST’s own threat table lists a look-up secret being stolen or copied, and paper can be photographed without leaving a mark. A sheet that names no account gives a finder far less to work with, which is a good reason to leave the account line for handwriting, or leave it blank.
A password manager is the other common home, and the same threat table is even-handed about it: passwords on paper can be disclosed, and a vulnerability in an insufficiently secure password manager can be exploited. The British guidance recommends managers and also notes that stored passwords are only as secure as your devices and accounts. The subtler cost is structural. The guideline insists that one authentication factor must not be usable to obtain another. Codes filed beside the password they back up collapse two steps into one vault.
Neither answer is wrong. What matters is that the copy does not sit on the one device whose loss it is meant to survive.
When a code is finally used, cross it off. The service will refuse it a second time. NIST goes further for recovery codes: after one is used, the service must invalidate it and issue a new one. In practice, treat the use of a backup code as a small alarm. Find out why the main method failed, and ask for a fresh set before the last one is gone, which makes the old sheet worthless to whoever finds it later.
Sources
Every source consulted for this guide. Links checked October 7, 2026.
- NIST Special Publication 800-63B National Institute of Standards and Technology (SP 800-63B-4, the current revision)
- NIST Special Publication 800-63B: Digital Identity Guidelines National Institute of Standards and Technology (Revision 3, superseded in 2025)
- SP 800-90A Rev. 1, Recommendation for Random Number Generation Using Deterministic Random Bit Generators NIST Computer Security Resource Center
- Randomness Requirements for Security RFC 4086, Internet Engineering Task Force
- Web Cryptography Level 2 World Wide Web Consortium (W3C)
- Crypto: getRandomValues() method MDN Web Docs, Mozilla
- Base 32 Douglas Crockford
- PKCS #5: Password-Based Cryptography Specification Version 2.1 RFC 8018, Internet Engineering Task Force
- PKCS #5: Password-Based Key Derivation Function 2 (PBKDF2) Test Vectors RFC 6070, Internet Engineering Task Force
- The scrypt Password-Based Key Derivation Function RFC 7914, Internet Engineering Task Force
- FIPS 180-4, Secure Hash Standard (SHS) NIST Computer Security Resource Center
- SP 800-132, Recommendation for Password-Based Key Derivation: Part 1: Storage Applications NIST Computer Security Resource Center
- Password Storage Cheat Sheet OWASP Cheat Sheet Series
- Setting up 2-Step Verification (2SV) National Cyber Security Centre (UK)
- Top tips for staying secure online | Managing your passwords National Cyber Security Centre (UK)
- 1.3.6.7.4. Critical Values of the Chi-Square Distribution NIST/SEMATECH e-Handbook of Statistical Methods
- ISO/IEC 7810 Wikipedia