Skip to content

Instantly share code, notes, and snippets.

@tresni
Last active February 19, 2024 08:00
  • Star 73 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save tresni/83b9181588c7393f6853 to your computer and use it in GitHub Desktop.
Authy to 1Password

Moving Authy to 1Password

1Password 5.3 for OSX, 5.2 for iOS, and 4.1.0.538 for Windows support OTP. I've been using Authy for a while now, but the fact is, I haven't really been using 2FA for some time. As mentioned by 1Password in a recent blog post, having the OTP generator and password on the same device is very much not 2FA. It's just an expiring OTP, which can help, but let's not kid ourselves too much.

With that out of the way. One of the things that was interesting to me was moving my OTP out of Authy and into 1Password. I like the control I get with 1Password, but I didn't want to have to reset all my OTP right away, that would suck. So, I got to dissecting the Authy Chrome App to see what I could do.

Run the Authy Chrome app and make sure it's unlocked.

Now, enable Developer mode in Chrome. We'll need this to inspect the background application that stores all the OTP information. It'll also tell you the Application ID for Authy (gaedmjdfmmahhbjefcbgaolhhanlaolb on my system) which is useful if you want to dive into the actual guts (which I did, a lot.)

Once Developer mode is enabled, click "main.html" next to "Inspect views:". We are going to inject the code below into main.html in order to get a pretty page we can use. On the console window that shows, copy/paste the javascript below and hit enter.

Viola! You can now use this page to move your OTP credentials to 1Password.

window.open('data:text/html;charset=utf-8,' + encodeURIComponent('<!DOCTYPE html>'+ '<html lang="en">'+ '<head><title>Embedded Window</title></head>'+ '<body>' +
  jQuery(require("models/apps/app_manager").get().getDecryptedApps()).map(function (ndx, elem) {
    if (!elem.decryptedSeed) { return }
    var name = elem.name || elem.originalName
    return "<h1><img src='" +
      require('models/assets/asset_manager').get().assetAccounts[elem.accountType].menuItemUrl + 
      "'>" + name + "</h1><h2>" + elem.decryptedSeed + "</h2>" +
      "<img src='https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/" + encodeURI(name) + "%3Fsecret%3D" + elem.decryptedSeed.toLowerCase() + "'/>"
}).toArray().join("<br>")
  + '</body>'+ '</html>' ) );

Minified (for copy/pasta)

window.open("data:text/html;charset=utf-8,"+encodeURIComponent('<!DOCTYPE html><html lang="en"><head><title>Embedded Window</title></head><body>'+jQuery(require("models/apps/app_manager").get().getDecryptedApps()).map(function(e,t){if(t.decryptedSeed){var r=t.name||t.originalName;return"<h1><img src='"+require("models/assets/asset_manager").get().assetAccounts[t.accountType].menuItemUrl+"'>"+r+"</h1><h2>"+t.decryptedSeed+"</h2><img src='https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/"+encodeURI(r)+"%3Fsecret%3D"+t.decryptedSeed.toLowerCase()+"'/>"}}).toArray().join("<br>")+"</body></html>"));
@Nomy
Copy link

Nomy commented Jan 21, 2018

Just confirming that the code from @akurtz still works.
I just used https://stefansundin.github.io/2fa-qr/ to generate QR code by pasting the URI in the otpauth field.

@JazzTech
Copy link

I'm trying to use the code mentioned above, but I think that Chrome has changed their Developer interface. When I go to Menu >> More tools >> Extensions, I see a bunch of blocks listing my installed Chrome extensions. I figured out that I need to click on the Inspect views background page to get to the code associated to the Authy extension. However, I'm lost after that.

Could someone help with the last few details to install the @akurtz code?

@fallen90
Copy link

fallen90 commented May 2, 2019

@JazzTech You can open the page chrome://extensions/?id=gaedmjdfmmahhbjefcbgaolhhanlaolb and in there, you should see main.html under Inspect views.

Oh and if no main.html is in the list, and the background page says (inactive) make sure to open the app first

@JazzTech
Copy link

JazzTech commented May 4, 2019

Thanks, @fallen90 - I have found that this thread is more active and more up-to-date on supporting Authy token exports.

@Roy-Orbison
Copy link

Neat idea, for sure, but not a fan of sending every private key over the wire to Google (or anyone). Would be great if your generated page could do it all client-side, e.g. include QRCode.js to create each image.

@lu-moreira
Copy link

Heya, looks like the Authy for chrome is no longer supported. But, still works. The only thing is part of the original code, in this case require functions, are missing now. But I was able to generate the QRCodes after changing to this

appManager.toJson().authenticatorApps
    .map(x => {
        return {
            title: x.account_type == 'authenticator' ? x.name : `${x.name} -> ${x.account_type}`,
            name: encodeURI(x.name || x.original_name),
            dec: x.decrypted_seed
        }
    })
    .map(x => {
        return {
            t: x.title,
            qr: `https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/${x.name}%3Fsecret%3D${x.dec.toLowerCase()}`
        }
    })
    .map(x => `<h1>${x.t}</h1><img src='${x.qr}'/>`)
    .join('<br><br>')

Important to mention, I wasn't able to use the window.open function, instead I just copied the result of this new function and used some html render to be able to do the process.

@tylerjgarland
Copy link

Looks like x.decrypted_seed is now null @lu-moreira but thanks for this snippet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment