otpa
Convert between plain otpauth:// links and Google Authenticator otpauth-migration://offline?data=... export links.
Inspired by dim13/otpauth.
Install
pipx install otpa
# or
pip install otpa
CLI
# -> otpauth-migration:// link(s)
otpa cm "otpauth-migration://offline?data=..."
otpa cm -f otpauth-links.txt # read links from a file
otpa cm -f otpauth-links.txt -n 5 # same as --batch-size 5 (cm only)
otpa cm -f a.txt -f b.txt link1 link2 # -f may repeat, combined with positional links
# -> otpauth:// links
otpa ca "otpauth-migration://offline?data=..."
otpa ca -f migration-links.txt
# interactively resolve accounts sharing the same secret/issuer
otpa cm -d "otpauth-migration://offline?data=..."
otpa ca -d "otpauth-migration://offline?data=..."
# open each output link as a QR code in your browser instead of printing them
otpa cm --qr "otpauth://totp/ACME:alice?secret=JBSWY3DPEHPK3PXP&issuer=ACME"
otpa ca --qr "otpauth-migration://offline?data=..."
# inspect either kind of link
otpa i "otpauth://totp/Example?secret=JBSWY3DPEHPK3PXP"
otpa i "otpauth-migration://offline?data=..."
-f/--file reads one link per line; blank lines and # comments are ignored.
Example
$ otpa ca "otpauth-migration://offline?data=CjEKCkhlbGxvId6tvu8SGEV4YW1wbGU6YWxpY2VAZ29vZ2xlLmNvbRoHRXhhbXBsZTAC"
otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&period=30
Library
from otpa import migration
# Expand a migration batch into otpauth:// links.
urls = migration.migration_to_otpauth("otpauth-migration://offline?data=...")
# Bundle otpauth:// links into one or more migration links
# (split across links when count > batch_size, default 10).
links = migration.otpauth_to_migration([
"otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example",
], batch_size=10)
# Lower-level access to the decoded protobuf payload.
payload = migration.migration_link_to_payload("otpauth-migration://offline?data=...")
for op in payload.otp_parameters:
print(op.name, op.issuer, migration.encode_secret(op.secret))
Release files for otpa 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| otpa-0.0.2.tar.gz | 13.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| otpa-0.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.2 kB
Release files / otpa-0.0.2.tar.gz
| Download URL | otpa-0.0.2.tar.gz |
|---|---|
| Size | 13.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6267098af2a1e1b39da2c541a895a4edd3080b20b4d19b7fce8a395ed9811ec8
|
|
BLAKE2b-256 checksum How to use checksums |
11106da6b93f4cd5332e7f5bd196e10e4b6f95a7e4ecb6f495cf31fa2b641f18
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / otpa-0.0.2-py3-none-any.whl
| Download URL | otpa-0.0.2-py3-none-any.whl |
|---|---|
| Size | 15.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3f823dec5397c2f3d5e776a10db14df28b862da4d03a649085ac3ea781e64423
|
|
BLAKE2b-256 checksum How to use checksums |
cf2d03c3acd9b5df20e5456a74d61cca29daf29bb0083680188a6b9f21dfa00e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|