Browser tool
Get your secret keys out of Google Authenticator.
Google Authenticator will show you a QR code holding every account on your phone, and then give you no way to read it. Screenshot that code, drop it here, and you get the base32 secret key and the otpauth link for each one.
The image never leaves this tab. Reading the QR code, parsing it and generating the codes all happen in your browser, and you can prove it by turning your network off and using the tool anyway.
The tool
Drop a screenshot of the export code
Or paste one, choose a file, or point your camera at the phone.
The decoding happens on your machine, in this tab, which is why it needs JavaScript to happen at all. There is no server here that could do it instead. Everything below explains the format and what the tool does with it, and the source is published if you would rather run it yourself.
Before you start
Treat that export code like a password.
Not a warning for form's sake. An export QR code is a more dangerous object than most people assume, in three specific ways worth knowing before you make one.
It holds every key, not a picture of your codes
The code contains the raw secret key for each account in it. Anyone who has the image can generate valid codes for those accounts indefinitely, from any device, without your phone and without you noticing.
Changing your password does not revoke it
Nothing about a new password, a new phone or deleting the app invalidates an exported secret. The only thing that does is switching two-factor authentication off and on again at each service, which issues a fresh key and retires the old one.
The screenshot outlives the moment
A screenshot lands in your camera roll and from there in whatever photo backup you have. Somebody who finds it in a year has exactly the access you had. Do this on a device you trust, and delete the image afterwards, including from the recently deleted album.
What comes back
Every field, and where each one came from.
The reason to do this properly is that you can tell decoded data from a sensible default. Both are shown, and they are labelled differently.
The secret key
RFC 4648 base32, uppercase and unpadded, exactly as an authenticator app displays it. Sixteen characters for a ten-byte key, thirty-two for a twenty-byte one. This is the whole credential. Everything else is metadata about it.
Issuer and account
The service and the account it belongs to. Google sometimes puts the issuer in its own field and sometimes folds it into the account label as “Issuer:account”, so both are read and both are shown, separately.
Algorithm, digits and type
Almost always SHA-1, six digits and time-based, because that is what services actually deploy. Where the export leaves one of them unset, the conventional default is used and the field is marked as a default rather than as data.
The otpauth link
A standard otpauth:// URI, rebuilt from the fields above rather than decoded, so it is precisely what another authenticator expects. Each one also gets a QR code, ready to scan straight into a different app.
The period, labelled honestly
Every account reports thirty seconds, and it is not decoded from anything. The export format has fields for the secret, name, issuer, algorithm, digit count, type and counter, and no field for the period at all. Google Authenticator uses thirty seconds for everything it exports, so that is what is reported, marked as a default so it is never mistaken for something that was in the code.
Counter-based accounts
A few accounts are counter-based rather than time-based, so their code does not rotate. The counter is shown as exported. Handle these carefully: using a code advances the counter at the service, and a copy that has fallen behind stops working.
How it works
It is five decodes, one after another.
None of this is cryptography and none of it needs a server. The chain is short enough to describe completely, which is worth doing, because the usual explanation is “install these three programs”.
The tool implements all five itself, with no third-party code. Reading the QR code is the largest part by a wide margin, because the browser will not do it for you: the built-in barcode detector is missing in Safari and Firefox, so the decoder is written from the specification.
01
Read the QR code
The image is reduced to black and white, the three corner finder patterns are located, a grid is fitted through them (in perspective, if the picture was taken at an angle), every module is sampled, and Reed-Solomon error correction repairs whatever the camera got wrong. Out comes a string beginning otpauth-migration://offline?data=.
02
Decode the data parameter
Percent-decoding that parameter gives standard base64, which decodes to a few dozen bytes. One trap is worth naming: it must not be read with a URL query parser, because those apply form decoding and turn a plus sign into a space, and standard base64 uses plus signs.
03
Parse the protocol buffer
Those bytes are an undocumented protobuf message holding a repeated account record, a version, a batch size, a batch index and a batch identifier. Each account record has seven fields: the raw secret, the name, the issuer, and numbers standing for the algorithm, digit count, type and counter.
04
Re-encode the secret as base32
The secret arrives as raw bytes. Authenticator apps display it as base32, so the bytes are encoded again to produce the string you would type into another app by hand.
05
Generate a code to check it
A time-based code is an HMAC of the current thirty-second interval under that key, truncated to six digits. The browser's own crypto does the HMAC, so there is no hand-rolled cryptography anywhere in this. If the code matches what your phone shows, the extraction is right, and that is the only check that really matters.
Privacy
The claim is narrow, and you can test it.
A privacy claim you cannot check is marketing. So here is the precise one, and the thing you can do in ten seconds to verify it.
Your image and your secrets are never transmitted
The image you drop in, the decoded payload, the secret keys and the generated codes stay in this tab. The code that handles them contains no call to fetch, XMLHttpRequest, WebSocket, EventSource or sendBeacon at all, and the offline build adds a content security policy so the browser enforces that rather than taking the code's word for it.
The test worth doing yourself
Switch your network off, reload this page from the cache or open the downloaded single-file version, and use the tool anyway. It works. Nothing that needed a server could.
What this page itself loads
Being exact, because the broader claim would be false: this page loads a small self-hosted analytics script that records the address of the page and nothing else. It goes nowhere near the tool and cannot see what you extract. If that still bothers you, the offline build has no external reference of any kind.
Nothing is stored
No cookies, no local storage, no session storage, no database, no cache. Reloading loses everything you had extracted, which is inconvenient once and correct always.
What clearing actually does
Clearing overwrites the secret bytes with zeroes. That is worth doing, and it is not memory scrubbing: strings in JavaScript cannot be overwritten, and the engine may hold copies that neither we nor you can reach. Closing the tab is what finishes the job, and no page can honestly claim more than that.
Published, and small enough to read
The whole thing is one MIT-licensed package with no runtime dependencies, so there is no supply chain behind it to audit. The QR decoder, the protobuf reader, the base32 and base64 codecs and the one-time password functions are all in it, and its tests are pinned to published test vectors rather than to itself.
Getting the code
Where the export code is hiding.
It is not called an export key or a backup, and it is not in the settings. Google files it under moving to a new phone, which is why most people never find it.
- 01Open Google Authenticator on the phone that holds the accounts.
- 02Open the menu, then choose Transfer accounts.
- 03Choose Export accounts, and authenticate when it asks.
- 04Tick the accounts you want and continue. A QR code appears.
- 05Screenshot that code, or point this tool's camera at the phone.
If you get more than one code
Google splits a long list across several QR codes and tells you which one you are on. Capture all of them and add them one after another. They share an identifier and each carries its own index, so they merge in any order and the tool says which parts are still missing. Codes from two different exports are refused rather than combined, because overlapping accounts from separate exports would produce a list that never existed on your phone.
Screenshot rather than photograph
A screenshot decodes first time. A photograph of a screen adds glare, moire and perspective, all of which the decoder handles and none of which it needs. If you are photographing somebody else's phone, fill the frame with the code and hold it square on.
Afterwards
What to do with a secret once you have it.
Move it into another app
Each account gets its own QR code here, in the format every authenticator reads, so you can scan it straight into a different app. Typing the base32 key in by hand works too, and is worth doing if you want to be certain nothing was mis-scanned.
Check one code against the phone
Before you rely on any of this, compare a generated code with what Google Authenticator shows for the same account at the same moment. If they match, the key is right. If they do not, the key is wrong and nothing else about the result matters.
Store it like a password
A secret key belongs in a password manager, in the entry for that account, not in a note or a spreadsheet. Some managers will generate the codes for you if you paste the otpauth link in. Worth thinking about first: a manager holding both the password and the second factor is a single point of failure, which may or may not be the trade you want.
Delete the capture
Including from the recently deleted album, and before your photo library syncs it anywhere. Then clear the tool and close the tab.
Detail
The specifics.
What the tool does and does not do, without the marketing. Every row here is asserted by the package's own tests.
- Runs
- Entirely in your browser. No server, no account, nothing to install.
- Reads
- Google Authenticator export codes (otpauth-migration), and single-account otpauth codes
- Input
- Drag and drop, paste, a file picker, or the device camera
- Output
- Base32 secret, issuer, account name, algorithm, digits, type, counter, otpauth link, an import QR code and a live code
- Network
- None. No fetch, XMLHttpRequest, WebSocket, EventSource or sendBeacon anywhere in the tool.
- Storage
- None. No cookies, local storage, session storage, database or cache.
- Offline
- Yes. A single-file build runs from your own disk with the network off.
- Browsers
- Chrome, Edge, Firefox, and Safari 16 or newer. The camera needs a secure page, so it may not open from a local file.
- Dependencies
- None at runtime. The QR codec, protobuf reader, base32 and base64 codecs and one-time password functions are all in the package.
- Licence
- MIT
Questions worth asking.
- Is it safe to put my export code into a website?
- The honest answer is that you should not put a credential into a page you cannot verify, which is why this one is verifiable. Nothing is transmitted, the source is published, and there is a single-file version you can download and run with your network off. If you would rather not trust a page at all, use that one.
- Does anything get sent to your servers?
- No, and there is nothing on our side that could receive it. The decoding, the parsing and the code generation all run in your browser. Open your browser's network panel, extract a code, and you will see no requests at all.
- Can I use it without an internet connection?
- Yes. Download the single HTML file from the repository's releases page and open it. It has no external reference of any kind and a content security policy that forbids connections outright. Everything works except the camera, which some browsers will not grant to a page opened from a file; dropping or pasting a screenshot always works.
- If somebody gets my export code, how do I revoke it?
- You cannot revoke a secret key on its own. Switch two-factor authentication off at the affected service and set it up again, which issues a new key and makes the old one useless. Changing your password does not do this, and neither does deleting the app or resetting the phone.
- Google gave me several QR codes. Now what?
- Capture all of them and add them one at a time. They share a batch identifier and each carries its own index, so they merge in any order and the tool tells you which parts are still missing. Re-adding one you already have is harmless. Codes from two different exports are refused rather than merged, because the combined list would be one that never existed on your phone.
- Why does every account say thirty seconds?
- Because the export format has no period field, and Google Authenticator uses thirty seconds for everything. The value is right and it is not decoded from anything, which is why it is labelled as a default rather than shown as data. If a service used a different interval, an export from this app would not tell you.
- One of my accounts has no rotating code.
- That is a counter-based account, and it is meant not to rotate. Its counter is shown as exported. Take care with it: using a code advances the counter at the service, so a copy that has fallen behind will stop being accepted.
- Which algorithms are supported?
- SHA-1, SHA-256 and SHA-512, using the browser's own crypto. MD5 appears in the format's list of algorithms but browsers cannot compute it, so no code is generated for one; the secret and every other parameter are still returned correctly. In practice services use SHA-1 with six digits, and Google Authenticator ignores anything else regardless.
- The camera does not work.
- It needs a secure page, so it will not open over plain http and may not open from a file address. A refusal tends to be remembered, so check the site settings in your browser. Whatever the camera does, dropping or pasting a screenshot works everywhere.
- It will not open my iPhone photo.
- iPhone photos are HEIC, and no browser except Safari will decode one. Take a screenshot instead of a photo, or convert the file to PNG or JPEG. A screenshot is the better input in any case, because it has no glare or perspective in it.
- Can I move these into a different authenticator?
- Yes. Each account has its own QR code in the standard otpauth format, which every authenticator app reads, and you can type the base32 key in by hand instead. Compare one generated code against your phone before you remove anything from it.
- I have seen this done with zbarimg and a Go program.
- That is the same three decodes with three installs in front of them: read the QR code, base64-decode the data parameter, parse the protobuf. This does all of it in a page, and the package behind it is published if you would rather script it. Nothing here wraps those tools; the QR decoder and the protobuf reader are written from their specifications.
Yours to keep, and yours to check.
One MIT-licensed package with no runtime dependencies. Read it, fork it, run it offline, or just use it here.
Read the source