Of all the data I moved this year, you probably wouldn't guess what I procrastinated on the longest.
Eighty-five thousand emails? Easy.
Twelve thousand photos? No problem.
Six hundred and seventy documents? Straightforward export.
I even made sure everything existed in at least two places. If the entire self-hosted stack were to implode tomorrow, I wouldn't lose anything truly irreplaceable. Recovery would be tedious, but possible.
The thirteen two-factor secrets in Authy were the exception.
For the longest time, they existed in exactly one place, and extracting them turned into the most boring afternoon of the entire migration. And I couldn't afford to keep putting it off, if I lost my phone or it died, getting back into my accounts would be far worse than tedious.
To understand why losing a TOTP seed can be worse than losing a password, it helps to understand how they work.
Passwords have recovery paths. You click "forgot password," get a reset link, pick a new one. Annoying, but who amongst us had not had to reset a password.
A TOTP seed is different. It's a shared secret, essentially a key that both you and the service hold to generate the same six-digit code at the same moment. When you scan that QR code during setup, you are seeing the only copy you will ever get. Lose it, and the service cannot show it to you again. Your only way back is to prove your identity through some other channel and disable two-factor entirely.
Some services offer backup codes. In theory, they solve this problem. In practice, I have never once managed to use them correctly. Ergonomically, they are a mess.
Wouldn't it be better to export and back up TOTP seeds securely?
Authy, which is owned by Twilio, offers encrypted cloud backups protected by a PIN. For some people, that's enough. For me, trusting Twilio with my TOTP seeds offended my sovereign sensibilities. Unfortunately, they offer no alternative export mechanism. A decision I made over a decade ago quietly locked me in.
This isn't a limitation of TOTP itself. It's a decision by Twilio.
TOTP is an open standard, defined in RFC 6238, created specifically to avoid proprietary 2FA systems. Any compliant app can generate the same codes from the same seed. The protocol should be portable by design.
Authy takes that portable protocol and makes it non-portable in practice.
If you ask, they'll probably say it's for your security: seeds that can't be exported can't be stolen via export. It's the same argument every walled garden makes. I don't buy it. I don't want a service that treats me as an adversary of myself, only I am allowed to do that.
When it came time to migrate, I looked into extracting my data. Community workarounds exist, but they involved patched apps and felt risky. Installing modified builds on my phone that I couldn't fully trust to handle my secrets would defeat the point.
So I sighed, procrastinated for a couple of weeks, and then decided to get it out of the way. For each of the thirteen accounts, I had to:
- Enter the password
- Enter the current Authy code
- Log in
- Navigate to security settings
- Enter the password again
- Enter another Authy code
- Disable two-factor
- Sometimes confirm via email
- Re-enable two-factor
- Scan the new QR code into my password manager
- Enter the new code
- Save recovery codes
- Delete the Authy entry
Thirteen times over.
Authy is free, but the real cost is the exit tax. An afternoon of tedious manual re-enrollment that would make most people think twice about leaving.
I paid the tedium tax. And now I'm free.
The seeds now live in my password manager, alongside their corresponding logins and recovery codes, encrypted, backed up, and replicated like everything else in the stack.
Some of you might raise an obvious objection: storing passwords and TOTP seeds in the same vault collapses two factors into one. If my password manager was breached, it would compromise both.
However.
My vault requires both a master password and a hardware security key. The key cannot be exported, copied, or phished, that's its entire purpose. So the chain remains two independent factors, i.e. something I know and something I have.
Whether that trade-off makes sense depends on your threat model, i.e. what is likely to happen to you, not what is theoretically possible. For me, this felt like the right choice.
I only wish I hadn't waited so long. The hardest part wasn't technical, it was tedious. And I can't shake the feeling that the tedium was totally by design.
This is part of the Autonomous Stack series, documenting my migration from proprietary services to self-hosted infrastructure.
Previously: I Cannot Be Trusted to Send Email.
Next: Self-Hosting the Blog.