TL;DR: Authy has no export and no desktop app anymore. The scripts and MITM tricks are dead. The one method that still works is a GDPR data request to Twilio for your own encrypted seeds, which you decrypt locally and bulk-load into 1Password with the op CLI. Migrated ~100 logins this way. Full steps below.
If you've been putting off moving off Authy, here's the whole playbook. 1Password has no bulk TOTP importer (you normally add one-time passwords one login at a time), so the op CLI at the end is the part that makes ~100 accounts bearable. I am located in the USA but still made the GDPR request.
Dead ends — skip these:
- Desktop-app debug export — app discontinued, backend blocks old versions.
- Device-registration scripts (alexzorin/authy) — killed by API attestation in 2024, repo archived.
- MITM the phone app — Authy detects TLS interception on jailbroken iOS and rooted Android and flags your account.
⚠️ Hard requirement: you MUST know your Authy Backup Password (Settings → Accounts → Backups). The export is AES-encrypted with it and there's no recovery without it.
Step 1: Email Twilio (privacy@twilio.com, cc support@twilio.zendesk.com):
Subject: GDPR Data Request — Authy Account Data Portability
Hello,
I am requesting a copy of my personal data under my right to data
portability (GDPR Article 20 / CCPA).
Specifically, I request an export of the encrypted secret seeds (TOTP
tokens) for every account registered in my Authy app, together with the
associated name, salt, iv, digits, and period values for each token.
My Authy account details for verification:
- Authy ID: <your Authy ID>
- Phone number: <your registered phone>
- Email address: <your registered email>
I can complete SMS and/or email verification as needed to confirm my identity.
Please provide the export in a machine-readable format (CSV or JSON).
Thank you,
<your name>
Asking for digits/period matters a few services use 7-digit/10s tokens and will produce wrong codes under the 6/30 default.
Step 2: Wait. You'll get a verification step (SMS/email), then the data. Mine took 9 days; they're allowed up to 30.
Step 3: The data. Two CSVs: one is metadata (names/devices), the other has the real name, encrypted_seed, salt, iv rows.
Step 4: Gotcha. If the CSV passed through Google Sheets/Excel, long base64 seeds get line-wrapped at 64 chars, splitting rows across two lines. Work from the raw file; rejoin any row that doesn't end in a 32-hex IV with the next line.
Step 5: Decrypt locally. Scheme: key = PBKDF2-HMAC-SHA1(backup_password, salt, 100000, 32 bytes) (salt as raw UTF-8), then AES-256-CBC with the hex iv, PKCS7-unpad → base32 secret. serbbil/Authy-GDPR-Export-Decryption does this and emits otpauth:// URIs.
Step 6: Verify first. Generate a code from one decrypted secret and compare to the live code in Authy. Match = they're all good. Don't uninstall Authy until you've confirmed.
Step 7: Bulk import into 1Password with the op CLI. For each decrypted otpauth:// URI:
op signin
op item create --category login --vault "Authy Import" \
--title "Amazon" \
"one-time password[otp]=otpauth://totp/Amazon secret=YOURSECRET&issuer=Amazon&digits=6&period=30"
Loop that over your decrypted list. I dumped them into a dedicated Authy Import vault so nothing existing got touched, then merged each OTP field into my real login and deleted the placeholder. (If you'd rather not script it, generate a QR per URI and scan each into the login's one-time-password field — slower but no CLI.)
Big caveat: Authy's "native" 7-digit tokens (Twilio, Cloudflare, Coinbase, SendGrid, etc. that integrated Authy directly) are not in the export. Re-enroll those by hand on each service.
Then clean up the plaintext seed files and you're done.