Backup Codes and 2FA Recovery Codes: Your Way Back In When the Phone Is Gone
What 2FA backup codes are, why each recovery code works only once, how to store them offline safely, and how to generate a batch locally in your browser.
Backup Codes and 2FA Recovery Codes: Your Way Back In When the Phone Is Gone
Two-factor authentication is great until the day your second factor walks out the door in your pocket. The phone gets dropped in a lake, the battery dies in an airport, the device gets wiped and the authenticator app's seeds go with it. At that exact moment, your carefully secured account becomes a locked vault that even you cannot open. Backup codes exist for that moment, and almost nobody saves them properly.
This post is about the unglamorous strip of characters that GitHub, Google, and Discord hand you the second you turn on 2FA. I want to explain what those codes actually are, why each one self-destructs after a single use, where to keep them so a single breach cannot take everything, and how to mint a fresh batch entirely on your own machine.
What a backup code really is
A backup code is a single-use recovery key for an account protected by two-factor authentication. Normally you log in with your password plus a rotating 6-digit token from an authenticator app. A backup code is the fallback that replaces that token when the app is unreachable. You type your password, the service asks for the second factor, and instead of the live token you enter one code from your saved sheet.
The detail that trips people up is that these are single-use 2FA fallbacks. Each code works exactly once. That is why providers never give you one code; they give you a batch. GitHub hands out roughly 16 codes the moment you enable 2FA. Google gives you 10 eight-digit codes. The idea is that you generate a set, store them offline, and burn through them one emergency at a time. A sheet of ten lets you recover up to ten times before you have to generate a new set.
Because every code is consumed on first redemption, a backup code seen over your shoulder or left in an old screenshot is worthless the moment you have spent it. The service marks it dead. That is the whole security model in one sentence: short-lived because each key dies after one use.
A worked example
Say you generate a sheet of one-time codes for a self-hosted Gitea account. It might look like this:
1. 4f8k2-9wp3h
2. qr7md-2x6vn
3. 8hc4j-mt9rk
4. zp3w6-7dq2f
5. 6kn9x-h4r8m
6. m2vt5-9cp7j
7. 9wd3k-4hx6n
8. rk7m2-8jq4p
9. 3hp9c-6mw2x
10. 7nx4k-2dr9h
Your phone goes missing on a Tuesday. You sit down at your laptop, open Gitea, and enter your password. It prompts for the 2FA token you can no longer produce. You click "use a backup code," look at your printed sheet, and type the first unused one: 4f8k2-9wp3h. You are in. You immediately cross that code off the sheet, because Gitea has now marked it spent. If you try 4f8k2-9wp3h again next month, it will simply be rejected. Nine codes remain. When you are down to one or two, you generate a fresh batch on the provider and retire the old sheet entirely.
That cross-it-off habit is the part people skip, and it is the part that keeps the sheet honest. A working copy that still lists spent codes is worse than useless in a panic.
Storing them offline, in more than one place
Here is where most people undo all the protection. They generate backup codes and paste them into a note on the same laptop that holds their password manager. One breach of that machine and an attacker has both factors at once: the vault and its emergency bypass. You have effectively turned two-factor authentication back into one factor.
The safer pattern is offline and redundant:
- Print the sheet and lock it in a drawer or a safe. Paper does not get exfiltrated over the network.
- Keep a second copy somewhere physically separate, so a fire or a lost bag does not erase your only route back in.
- If you genuinely need a digital copy, put it inside an encrypted vault entry, not a loose plaintext note. An entry in your manager is fine; a
codes.txton the desktop is not.
Digit-only codes are worth a mention here. If you might be reading them off a printout in dim light or copying them by hand, plain numbers are far less error-prone than dense letter-and-digit strings. A read-aloud sheet you can dictate over a phone call has real value when you are standing in a foreign airport with a dead handset.
Generating a batch locally
You do not have to rely on a provider's flow to understand or practice this, and you should never trust a website that generates recovery codes and could be quietly logging them. The right way is fully local generation: the codes are produced by JavaScript running inside your own browser tab, with nothing sent to a server.
The Backup Codes Generator does exactly that. It builds a sheet of N codes (10 by default), each split into even groups like xxxxx-xxxxx or xxxx-xxxx-xxxx, drawn from pure digits or from letters and digits with the look-alike glyphs 0 O 1 I l stripped out so a handwritten copy stays legible. Every code comes from crypto.getRandomValues, the operating-system-backed cryptographic random source, never Math.random, and each code is guaranteed unique within the batch. You see the entropy per code, copy the whole set, download it as a plain .txt to print, and tick off each code as you spend it.
Nothing is uploaded, and the codes never ride in the URL. Only the format options, the count, the grouping, the separator, and the character set, get encoded in a shareable link; the secrets themselves never leave your tab. You can match GitHub's grouped shape, Google's eight-digit shape, or your own provider's layout, then store the printed sheet offline.
If you are setting all of this up from scratch, it pairs naturally with a TOTP Generator so you can see the live token and the backup codes side by side and understand exactly which one you are reaching for in an emergency.
My own near-miss
I learned this the hard way. A couple of years ago I migrated to a new phone, restored from a backup that did not include my authenticator app, and only then realized the app had no cloud sync. Every TOTP seed was gone. For two of my accounts I had saved backup codes; for one I had not. The two with codes took me ninety seconds each to recover. The third turned into a week of identity verification, support tickets, and a scanned passport photo before a human finally let me back in. Since then I generate a sheet the same day I enable 2FA on anything, print it, and file it. The whole ritual costs about three minutes and has saved me hours.
The short version
Backup codes are the boring insurance you only appreciate the day everything else fails. Treat them as what they are: single-use keys, generated in a batch, stored offline in more than one place, crossed off as you spend them, and regenerated before you run out. Make them locally so the secrets never touch a server, keep the paper somewhere a network breach cannot reach, and the lost-phone scenario becomes a ninety-second annoyance instead of a week-long ordeal.
Made by Toolora · Updated 2026-06-13