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>"));