Client-side / No data sent

TOTP QR Decoder

Decode a 2FA QR code image, an otpauth:// link, a Base32 secret, or a Google Authenticator export QR — and see the live one-time passwords. Everything runs in your browser — nothing is uploaded.

For your own accounts only.

What you can decode

What you can decode here

A QR code image
PNG, JPG, JPEG, GIF, BMP or WebP. Drag it in, click to browse, or paste it with Ctrl+V. A screenshot works, and so does a photo of another screen — useful when the app blocks screenshots.
An otpauth:// URL
Paste the link itself, for example otpauth://totp/ACME:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME.
A raw Base32 secret
Something like HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ. Spaces, dashes and lowercase letters are fine — they get normalised.
A Google Authenticator export QR
The otpauth-migration://offline?data= format, which holds several accounts in one code. All of them are decoded at once.

For every account you get a live six-digit code with a countdown, the Base32 secret, the full otpauth:// URL, and a freshly generated QR code you can scan into another app.

How to decode a Google Authenticator export QR code

  1. Export from the app. In Google Authenticator, open the menu → Transfer accounts → Export accounts, then pick the accounts you want. Google packs at most ten accounts into one QR code; with more, it produces several codes in sequence.
  2. Capture the code. On Android the export screen blocks screenshots, so the reliable way is to photograph the screen with a second phone or a camera. That photo decodes here just fine.
  3. Decode it. Drop the photo or screenshot above — or, if you already have the string, paste otpauth-migration://offline?data=… directly.
  4. Import where you need it. Each account gets its own QR code and otpauth:// URL, so you can add them to another authenticator one at a time.

The export QR code won't scan

A code carrying ten accounts is dense, and dense codes fail to read — especially from a photo taken at an angle or in poor light. The fix that reliably works is exporting in smaller batches of about four accounts: each code becomes sparser and scans on the first try. Repeat the export as many times as you need.

What is inside an otpauth-migration URL

The data parameter is base64url-encoded protobuf. Inside sits a MigrationPayload message with a repeated list of OtpParameters — one entry per account, each holding the raw secret bytes, the label, the issuer, and the algorithm, digit and type enums. This page parses that structure locally and re-encodes each secret to Base32.

Move your 2FA codes to a new phone or another app

Decode the export first, store the secrets somewhere you trust, then verify that you can actually log in to two or three accounts from the new device. Only after that should you remove anything from the old phone or wipe it — a secret you never tested is not a backup.

The otpauth:// URLs and per-account QR codes import into Aegis, Ente Auth, 2FAS, Bitwarden, 1Password, KeePassXC, Proton Pass and most other authenticators — one code at a time.

Two things this tool cannot help with, to save you the attempt: Microsoft Authenticator does not export its secrets in any readable form, and Steam Guard uses its own format rather than an otpauth:// QR code.

Is it safe to decode a 2FA QR code here?

The sensible default is to never paste TOTP secrets into an online service, and that advice is correct — most QR decoders on the web send your image to a server. The difference here is architectural: there is no server to send it to.

The image is read by jsQR on a canvas in the page, migration payloads are parsed by protobufjs, and codes are computed by totp-generator. No step makes a network request with your data. There is no backend, no form submission, and nothing is written to storage.

Verify it yourself

  • Open DevTools → Network, clear it, then decode something. No request carries your QR contents.
  • Turn off your network after the page has loaded. Decoding keeps working.
  • Read the source: github.com/VizzleTF/TOTP_decoder.
  • Save the page and its bundle, then open the file from disk with no connection at all.

One honest caveat: the page does load an anonymous visit counter (Vercel Analytics), which reports the URL and nothing else. It has no access to your QR contents, secrets or generated codes — but it is a network request, so you will see it in DevTools and you should know what it is.

When to use an offline tool instead

Your trust here rests on the code being delivered honestly over HTTPS. That is a real assumption: whoever controls the hosting could in principle serve different JavaScript. For high-value secrets — corporate accounts, crypto exchanges — run a local tool on a machine that is offline, such as scito/extract_otp_secrets or dim13/otpauth.

otpauth:// URL format reference

A complete TOTP URL looks like this:

otpauth://totp/ACME%20Co:john.doe@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30

Parameter Required Values Default
type yes totp | hotp
label yes Issuer:Account, URL-encoded
secret yes Base32, A–Z and 2–7
issuer no service name
algorithm no SHA1 | SHA256 | SHA512 SHA1
digits no 6 | 8 6
period no seconds, TOTP only 30
counter HOTP only integer

Many authenticators quietly ignore algorithm and digits and just assume SHA-1 with six digits, which is why a code can look wrong even when the secret is right. Unrecognised parameters should simply be ignored by whatever reads the URL.

Base32 secrets: length and common errors

Secrets are usually 16, 26 or 32 characters. The Base32 alphabet is A–Z plus the digits 2–7 only, so if your string contains 0, 1, 8 or 9, it is not Base32 — that is the usual cause of an "invalid secret" error. Trailing = padding is optional, and case does not matter.

FAQ

Does my QR code or secret get uploaded anywhere?

No. Decoding happens in your browser and there is no backend to receive anything. The only network request after page load is an anonymous visit counter that sees the URL and nothing else.

Can I decode an export QR with several accounts at once?

Yes. A otpauth-migration:// payload holds up to ten accounts and all of them are listed separately, each with its own code, secret and QR.

Why can't I screenshot the export QR code?

Google Authenticator marks the export screen as secure on Android, which blocks screen capture. Photograph the screen with another device and upload the photo instead.

My export QR code won't scan. What do I do?

Export fewer accounts per code — around four is a good target. The resulting QR is much less dense and reads reliably from a photo.

How long should a TOTP secret be?

In practice 16 to 32 Base32 characters, which is 80 to 160 bits. Anything shorter than 16 characters is unusually weak; anything using digits outside 2–7 is not Base32 at all.

My code is rejected even though the secret is right. Why?

Usually the device clock has drifted — TOTP is time-based, so even a minute of skew breaks it. Otherwise check that period, digits and algorithm match what the service actually expects.

Can I use this to move codes into Bitwarden, Aegis or 1Password?

Yes — each account here produces a standard otpauth:// URL and a scannable QR code, which is exactly what those apps accept.

Does it work with Microsoft Authenticator?

No. Microsoft Authenticator has no way to export its TOTP secrets or show them as a QR code, so there is nothing to decode.

Does it work with Steam Guard?

No. Steam stores its shared secret in its own file format rather than an otpauth:// QR code, so this tool does not apply.

Is this open source?

Yes, MIT licensed. The full source is at github.com/VizzleTF/TOTP_decoder.