Twilio provides no way to export your Authy tokens. This leaves you either locked into the app or forced to manually reset 2FA on every account. However, the GDPR's data portability right (Article 20) legally requires Twilio to hand over your data on request.
That data arrives as a CSV in which every token is encrypted with your backup password.
authy-migrate is a Python command-line utility that unlocks each one and rewrites them
as an Aegis vault or plain otpauth:// URIs.
So you can migrate your codes over to any standard authenticator app.
Authy provides no direct export, so you must submit a data portability request to Twilio:
.csv file containing your tokens.pip install -r requirements.txt
python authy_migrate.py [options] <tokens.csv>
You will be prompted for your Authy backup password, and the output files are written next to the input CSV by default.
| Option | Default | Description |
|---|---|---|
-o, --output-dir PATH | Same directory as input | Directory for output files |
-p, --password TEXT | Prompted | Backup password |
--format {aegis,uris,both} | both | Output format |
--aegis-file NAME | tokens_aegis.json | Filename for the Aegis JSON export |
--uris-file NAME | otpauth_uris.txt | Filename for the otpauth URI list |
[!WARNING] Avoid passing
--passwordon the command line. It is visible to other users on the same system viapsand is recorded in your shell history. Let the script prompt you instead.
# Prompt for the password; write both formats next to the CSV
python authy_migrate.py "Authy Personal Information Request - Tokens.csv"
# Write only the Aegis JSON to a custom directory
python authy_migrate.py tokens.csv -o ~/exports --format aegis
| File | Compatible with |
|---|---|
tokens_aegis.json | Aegis vault (db v3) - Aegis (Android) natively; Proton Authenticator, 2FAS and others that support Aegis import |
otpauth_uris.txt | Plain-text URIs accepted by most open-source authenticators; some apps (e.g. Google Authenticator, iOS Passwords) only import URIs via QR code |
[!IMPORTANT] Delete the output files immediately after importing - they contain plaintext TOTP secrets. The export CSV holds encrypted secrets but should still be treated as sensitive.
Your one backup password re-derives the key that unlocks every token, and the script uses it to turn each encrypted row back into a secret any authenticator understands. It runs in three moves:
name, encrypted_seed, salt, and iv). Authy adds stray quotes to the export -
older backups wrap the whole file in one pair, newer ones wrap every line in its own
pair. The script detects the wrapping format from the header and removes that
wrapper while preserving ordinary CSV field quotes.salt are stretched
into a 32-byte key (PBKDF2), which then decrypts the encrypted_seed with AES. The result
is the base32 TOTP secret - the short string that actually generates your 6-digit codes.otpauth:// URIs, each written owner-only (0600).A wrong backup password produces garbage that fails a final validity check, so every row fails together. The script notices that nothing decrypted and stops telling you the password was likely wrong.
Under the hood, Authy encrypts each backup seed with the scheme below, which this tool reverses:
Key = PBKDF2-HMAC-SHA1(password, salt_utf8, iterations=100000, dklen=32)
Data = AES-256-CBC(key, iv_hex, base64(encrypted_seed))
If you cannot wait for the GDPR export and have an iPhone and a Mac, authy-exit captures the encrypted tokens from Authy's own sync traffic via a local proxy instead, and targets Bitwarden rather than Aegis. It uses the same decryption scheme as this tool but is a considerably more involved setup (TLS interception, certificate trust, an iPhone backup for account metadata).
This project is licensed under the MIT License - see the LICENSE file for details.
Authy is a trademark of Twilio Inc. This project is independent and has no affiliation with, or endorsement by, Twilio Inc.
7 commits
Python
100.0%
Twilio provides no way to export your Authy tokens. This leaves you either locked into the app or forced to manually reset 2FA on every account. However, the GDPR's data portability right (Article 20) legally requires Twilio to hand over your data on request.
That data arrives as a CSV in which every token is encrypted with your backup password.
authy-migrate is a Python command-line utility that unlocks each one and rewrites them
as an Aegis vault or plain otpauth:// URIs.
So you can migrate your codes over to any standard authenticator app.
Authy provides no direct export, so you must submit a data portability request to Twilio:
.csv file containing your tokens.pip install -r requirements.txt
python authy_migrate.py [options] <tokens.csv>
You will be prompted for your Authy backup password, and the output files are written next to the input CSV by default.
| Option | Default | Description |
|---|---|---|
-o, --output-dir PATH | Same directory as input | Directory for output files |
-p, --password TEXT | Prompted | Backup password |
--format {aegis,uris,both} | both | Output format |
--aegis-file NAME | tokens_aegis.json | Filename for the Aegis JSON export |
--uris-file NAME | otpauth_uris.txt | Filename for the otpauth URI list |
[!WARNING] Avoid passing
--passwordon the command line. It is visible to other users on the same system viapsand is recorded in your shell history. Let the script prompt you instead.
# Prompt for the password; write both formats next to the CSV
python authy_migrate.py "Authy Personal Information Request - Tokens.csv"
# Write only the Aegis JSON to a custom directory
python authy_migrate.py tokens.csv -o ~/exports --format aegis
| File | Compatible with |
|---|---|
tokens_aegis.json | Aegis vault (db v3) - Aegis (Android) natively; Proton Authenticator, 2FAS and others that support Aegis import |
otpauth_uris.txt | Plain-text URIs accepted by most open-source authenticators; some apps (e.g. Google Authenticator, iOS Passwords) only import URIs via QR code |
[!IMPORTANT] Delete the output files immediately after importing - they contain plaintext TOTP secrets. The export CSV holds encrypted secrets but should still be treated as sensitive.
Your one backup password re-derives the key that unlocks every token, and the script uses it to turn each encrypted row back into a secret any authenticator understands. It runs in three moves:
name, encrypted_seed, salt, and iv). Authy adds stray quotes to the export -
older backups wrap the whole file in one pair, newer ones wrap every line in its own
pair. The script detects the wrapping format from the header and removes that
wrapper while preserving ordinary CSV field quotes.salt are stretched
into a 32-byte key (PBKDF2), which then decrypts the encrypted_seed with AES. The result
is the base32 TOTP secret - the short string that actually generates your 6-digit codes.otpauth:// URIs, each written owner-only (0600).A wrong backup password produces garbage that fails a final validity check, so every row fails together. The script notices that nothing decrypted and stops telling you the password was likely wrong.
Under the hood, Authy encrypts each backup seed with the scheme below, which this tool reverses:
Key = PBKDF2-HMAC-SHA1(password, salt_utf8, iterations=100000, dklen=32)
Data = AES-256-CBC(key, iv_hex, base64(encrypted_seed))
If you cannot wait for the GDPR export and have an iPhone and a Mac, authy-exit captures the encrypted tokens from Authy's own sync traffic via a local proxy instead, and targets Bitwarden rather than Aegis. It uses the same decryption scheme as this tool but is a considerably more involved setup (TLS interception, certificate trust, an iPhone backup for account metadata).
This project is licensed under the MIT License - see the LICENSE file for details.
Authy is a trademark of Twilio Inc. This project is independent and has no affiliation with, or endorsement by, Twilio Inc.
7 commits
Python
100.0%