🔐 Simple, local-only Authy TOTP exporter and converter.
A no-fluff, single-file workflow to export and decrypt your Authy TOTP tokens locally. Capture the Authy API response with mitmweb, save the JSON, then run authy_exporter.py and enter your Authy backup password to produce OTPAuth URLs and Bitwarden-compatible exports. Everything you need is in this README.
- Credits: this guide was assembled with help from community projects such as
BrenoFariasdaSilva/Authy-iOS-MiTM(see Credits & References below).
No jailbreak required: you do NOT need a jailbroken device. All you need is:
-
A computer (Windows/macOS/Linux) to run
mitmweband the Python decrypter script. -
An iOS device with Authy installed and a created Authy backup password.
-
The mitmproxy certificate installed & trusted on the device (instructions below).
-
This README — full step-by-step instructions are provided below.
-
Step-by-step guide (this section)
-
Troubleshooting anchors (bottom of file)
-
Script usage (
python authy_exporter.py --help)
Follow these steps in order — this is the single, canonical guide. Troubleshooting and edge-case fixes are linked in the Troubleshooting section below. This README is the only detailed, newbie-friendly guide you need; the docs/ folder has been retired so you can stay in one file.
Windows (PowerShell)
- Download Python from https://www.python.org/downloads/ and run the installer. During setup, check Add Python to PATH and choose Install Now; alternatively install via winget:
winget install --id Python.Python.3 -e --source winget- Open a new PowerShell window and confirm Python and pip are available:
python --version
pip --versionIf these commands show "not found" or "command is not recognized," click here for Windows PATH & PowerShell troubleshooting.
- Create and activate a virtual environment:
python -m venv venv
venv\Scripts\Activate.ps1If PowerShell refuses to run Activate.ps1, click here for the execution policy fix.
- Upgrade pip and install the Python packages you need:
python -m pip install --upgrade pip
pip install cryptography mitmproxyIf pip install fails, click here for install fixes on Windows/macOS/Linux.
macOS (Homebrew)
- Install Homebrew if you do not already have it:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)". - Use Homebrew to install Python and mitmproxy:
brew update
brew install python
brew install mitmproxy- Create+activate a virtual environment and install dependencies:
python3 -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
pip install cryptography mitmproxyIf any install step breaks, click here.
Linux (Debian / Ubuntu)
- Install Python and helper packages:
sudo apt update
sudo apt install -y python3 python3-venv python3-pip- Create and activate a virtualenv, then install pip dependencies:
python3 -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
pip install cryptography mitmproxyIf anything fails (SSL errors, missing packages), click here.
- Open Authy on your phone → Settings → Accounts → Create Backup Password.
- Set a strong password and write it down temporarily; you will enter it when the script runs in step 6.
- Run mitmweb from the activated virtualenv or system shell:
mitmweb- Keep the terminal open; note the web interface at
http://127.0.0.1:8081and that the proxy listens on port8080. - On your iPhone Wi-Fi settings, set HTTP Proxy to Manual and enter your computer's IPv4 address (find it with
ipconfigorip addr show) plus port8080. - On the phone, open Safari and visit
http://mitm.it, install the mitmproxy profile, then trust it via Settings → General → About → Certificate Trust Settings.
If the proxy does not load traffic, click here. If certificate installation fails or HTTPS requests give security warnings, click here.
- In the mitmweb interface, type in the search bar:
~d "api.authy.com" token
- In Authy on the phone, go to Settings → Accounts, toggle Backup to OFF, and when prompted, tap Don't Disable (this triggers the API request without deleting your backup password).
- Switch back to mitmweb, find the GET request to
api.authy.com, and open it. The request URL will look likehttps://api.authy.com/json/users/...&apps=123,... - Copy the full URL, paste it into a text editor, and delete everything after
apps=(leave the trailingapps=). You must trim it before pasting it into your browser or curl.
Example request you should see in mitmweb:
https://api.authy.com/json/users/63351862/authenticator_tokens?locale=en&api_key={api_key_here}&otp2={otp_2_here}&otp3={otp_3_here}&device_id={device_id_here}&apps={list_of_app_ids}When trimmed, the URL should end with apps= (no app IDs). Paste that trimmed URL into your browser.
Example trimmed request
https://api.authy.com/json/users/63351862/authenticator_tokens?locale=en&api_key={api_key_here}&otp2={otp_2_here}&otp3={otp_3_here}&device_id={device_id_here}&apps={list_of_app_ids}If the trimmed URL returns HTML or redirects, click here for alternate download commands.
- Paste the trimmed URL into your computer browser and press Enter.
- From the response page, choose View Source / Raw Data, copy the entire JSON payload, and save it as
authenticator_tokens.jsonin the same folder asauthy_exporter.py. - After saving, make sure the JSON starts like this example (each field should be present for each token):
{
"message": "success",
"authenticator_tokens": [
{
"account_type": "{name of account}",
"digits": "{digits}",
"encrypted_seed": "{seed_here}",
"issuer": "{issuer}",
"key_derivation_iterations": "{iterations}",
"logo": "{logo}",
"name": "{name}",
"original_name": "{original_name_here}",
"password_timestamp": "{pw_timestamp}",
"salt": "{salt_here}",
"unique_id": "{uid_here}",
"unique_iv": "{uiv_here}"
}
]
}- Double-check the file contains the
authenticator_tokensarray andencrypted_seedfields for each entry.
If browsers still show HTML or you prefer a CLI download, click here for curl/wget commands.
- Run the exporter script (it will prompt for the Authy backup password created in Step 2):
python authy_exporter.py- Enter the backup password when prompted. The script decrypts the tokens and writes an export file such as
authenticator_tokens_export_bitwarden.json, and printsotpauth://URLs you can copy.
If you see Decryption failed or invalid data, click here for checks.
See example commands for running the script in the "Script examples" section: click here.
- For Bitwarden bulk import: log into https://vault.bitwarden.com → Settings → Tools → Import Data, select Bitwarden (json), and upload the exported JSON file.
- Alternatively, open the export, copy the
decrypted_seedfor a specific account, and paste it into that login item under Authenticator Key (TOTP). - After importing, delete
authenticator_tokens.json, the export file, stopmitmweb(Ctrl+C), and remove the HTTP proxy configuration from your iPhone Wi-Fi settings. - Uninstall the mitmproxy profile: Settings → General → VPN & Device Management → mitmproxy → Delete Profile, then disable the trust toggle under Certificate Trust Settings.
If Bitwarden rejects the JSON or shows errors, click here; for cleanup reminders revisit the Security Notes below.
Use these copy-and-paste commands once you have authenticator_tokens.json and your backup password ready:
-
List every supported export format
python authy_exporter.py --list-formats
-
Export to Bitwarden (default)
python authy_exporter.py
-
Export to Google Authenticator format
python authy_exporter.py --format google
-
Export to LastPass CSV with a custom JSON input file
python authy_exporter.py -i my_tokens.json -f lastpass
-
Get plain-text output with OTPAuth URLs (good for manual copy/paste)
python authy_exporter.py --format text
Each command prompts you for the Authy backup password (you set it in Step 2). After the script finishes, you can find the exported file next to authenticator_tokens.json — the file name follows the pattern <input>_export_<format>.<ext>.
Advanced troubleshooting and a collection of fixes for path/cert/proxy issues are available in this community gist:
If the quick fixes below don't resolve your issue, check the gist for additional steps and user-contributed solutions.
Problem: iOS doesn't trust the mitmproxy certificate.
Solution:
- Go to Settings → General → About → Certificate Trust Settings
- Make sure the mitmproxy toggle is enabled
Problem: Proxy isn't configured correctly.
Solution:
- Verify your iPhone proxy settings match your computer's IP and port 8080
- Make sure mitmweb is still running
- Try visiting
http://example.comin Safari - you should see it in mitmweb
Problem: Wrong backup password or corrupted data.
Solution:
- Verify you're using the correct backup password from Authy
- Try exporting the tokens again from the API
- Make sure the JSON file is valid (check for syntax errors)
Problem: Authy changed their flow or you didn't trigger the request correctly.
Solution:
- Make sure you set the filter in mitmweb:
~d "api.authy.com" token - Try toggling the backup switch off then immediately tap "Don't Disable"
- Look for any request to
api.authy.comin mitmweb (even without the filter)
Problem: JSON format is incorrect.
Solution:
- Open
bitwarden_import.jsonand verify it's valid JSON - Make sure it has the structure:
{ "encrypted": false, "items": [...] } - Try importing just one item first to test
🔒 Important Security Considerations:
⚠️ Delete sensitive files after import:authenticator_tokens.json,bitwarden_import.json⚠️ Remove the proxy from your iPhone after you're done:- Settings → Wi-Fi → (i) → HTTP Proxy → Off
⚠️ Uninstall the mitmproxy certificate from your iPhone:- Settings → General → VPN & Device Management → mitmproxy → Delete Profile
- Settings → General → About → Certificate Trust Settings → Disable mitmproxy
⚠️ Never share your API keys, device IDs, or OTP codes⚠️ Never commit these files to git (the.gitignoreprotects you)- ✅ Use a strong master password in Bitwarden to protect your TOTP codes
If Windows reports python or pip as not found, or PowerShell refuses to run Activate.ps1, follow these steps.
- Verify Python is installed via the python launcher
py:
py -3 --versionIf py returns a version, use py -3 -m venv venv and venv\Scripts\Activate.ps1 instead of python.
- Add Python to PATH (if you used the installer and forgot to check "Add Python to PATH"):
- Re-run the installer and choose "Modify" → check "Add Python to PATH" → Continue, or
- Manually add the Python installation directory (e.g.,
C:\Users\<you>\AppData\Local\Programs\Python\Python39\) and the Scripts folder to your PATH via System → Advanced → Environment Variables → EditPath.
Then open a NEW PowerShell window and run:
python --version
pip --version- PowerShell execution policy prevents scripts from running (common when activating venv):
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserThis allows local scripts (like Activate.ps1) to run for your user. To revert later:
Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope CurrentUser- If
py/pythonstill aren't working, use the full path to the executable as a workaround, for example:
C:\Users\yourname\AppData\Local\Programs\Python\Python39\python.exe -m venv venvIf mitmweb is running but you don't see requests from your phone, try these steps in order:
- Confirm
mitmwebis running and showing the web UI athttp://127.0.0.1:8081on your computer.
mitmweb-
Verify your phone's Wi‑Fi HTTP Proxy is set to your computer's IP and port
8080(Manual). See the Step‑by‑Step section for how to find your IPv4 address. -
Ensure your computer and phone are on the same Wi‑Fi network. Disable VPNs on the phone and the computer while capturing.
-
Check firewall rules on your computer — temporarily allow
mitmproxy/pythonor the listening port8080. -
Visit
http://mitm.iton the phone and re-install the mitmproxy profile; then re-enable the Certificate Trust toggle under Settings → General → About → Certificate Trust Settings. -
If the request still does not appear, open mitmweb logs (the terminal running mitmweb) and look for errors or dropped connections.
-
Common gotcha: when copying the request URL from mitmweb, make sure you copy the full request URL (including
apps=) and then trim everything AFTERapps=(leaveapps=but remove app ids). If you paste a malformed URL into the browser, it may redirect or return HTML instead of raw JSON. -
External docs: if these steps don't help, the official mitmproxy docs have extra details on certs, proxying, and troubleshooting: https://docs.mitmproxy.org/stable/
If pip install or platform package installs fail, try these step‑by‑step fixes depending on your OS.
macOS (Homebrew):
brew update
brew install python
brew install mitmproxyDebian/Ubuntu:
sudo apt update
sudo apt install -y python3 python3-venv python3-pipIf pip install mitmproxy fails with build or SSL errors, upgrade pip and install wheel first:
python -m pip install --upgrade pip setuptools wheel
pip install mitmproxyIf you encounter SSL certificate errors while installing packages on macOS, run the Install Certificates.command that ships with the Python installer (path may vary):
/Applications/Python\ 3.x/Install\ Certificates.commandIf your browser shows HTML or redirects instead of raw JSON, try one of these alternatives:
- Use
curlto fetch the trimmed URL directly (replace the URL you copied):
curl -L "<paste-the-trimmed-url-here>" -o authenticator_tokens.json- Use
wget:
wget -O authenticator_tokens.json "<paste-the-trimmed-url-here>"- If you see a login page or redirect, confirm you trimmed the URL so it ends with
apps=(remove app ids). A malformed URL can return HTML instead of JSON.
If authy_exporter.py reports Decryption failed or produces invalid seeds, follow these checks in order:
- Confirm you created the Authy backup password in Step 1 and that you type it exactly (no leading/trailing spaces).
- Ensure
authenticator_tokens.jsoncontains theauthenticator_tokensarray and valid fields; validate withjqor https://jsonlint.com/. - Try decrypting a single token with the script using
-ito point at a minimal JSON containing just one token to isolate failures. - If you see KDF iteration mismatches or base64 errors, re-export the JSON using
curl/wget(see "Saving / Viewing Raw JSON Troubleshooting") and retry.
If these steps don't help, consult the troubleshooting gist linked above or open an issue with the exact error output and a sanitized sample of the token JSON.
If Bitwarden refuses to import the JSON file:
- Validate the JSON structure at https://jsonlint.com/.
- Ensure the top-level structure matches Bitwarden's expected format:
{"encrypted": false, "items": [ ... ]}. - If Bitwarden complains about missing fields, open the JSON and inspect one item to confirm
nameandlogin/notesare present. - As a test, create a minimal JSON file with a single item and try importing that to find the problematic item.
If http://mitm.it appears to install the profile but you still see certificate errors or no HTTPS traffic:
- Delete any existing mitmproxy profile on the iPhone: Settings → General → VPN & Device Management → mitmproxy → Delete Profile.
- Reboot the iPhone.
- Re-open Safari and go to
http://mitm.itto reinstall the profile; then enable trust under Settings → General → About → Certificate Trust Settings. - Ensure the phone's date/time are correct and that no MDM policy blocks profile installation.
- If you get
Decryption failed, re-check that you created the Authy backup password beforehand and typed it correctly when prompted. See Step 1 above. - If Bitwarden import fails with a JSON error, open the export in a text editor and validate it via https://jsonlint.com/.
After successfully importing to Bitwarden:
# Delete sensitive files
rm authenticator_tokens.json
rm bitwarden_import.json
# Stop mitmweb (Ctrl+C in the terminal)
# Remove proxy from iPhone (see Security Notes above)
# Optional: Uninstall mitmproxy
pip uninstall mitmproxyauthy-to-bitwarden/
├── authy_exporter.py # Main decryption script (canonical entrypoint)
├── requirements.txt # Python dependencies
├── README.md # This file
├── LICENSE # MIT License
├── .gitignore # Protects sensitive files
├── authenticator_tokens.json # Your encrypted tokens (not tracked)
└── authenticator_tokens_export_bitwarden.json # Decrypted output (not tracked)
MIT License - see LICENSE file for details.
This tool is for personal use only to migrate your own authenticator tokens. Always keep secure backups of your TOTP codes. The authors are not responsible for any data loss or security issues.
By using this tool, you acknowledge:
- You understand the security implications of intercepting HTTPS traffic
- You will properly clean up certificates and proxies after use
- You will securely delete sensitive files after import
- This is only for migrating your own personal data
- Built with mitmproxy
- Uses Python cryptography library
If you encounter issues:
- Check the Troubleshooting section
- Verify all steps were followed correctly
- Open an issue on GitHub with details about your error
Happy migrating! 🎉