Generate Time-Based One-Time Passwords With JavaScript

I recently released an iOS and Android application called OTP Safe to iTunes and Google Play.  OTP Safe makes use of the time-based one-time password (TOTP) algorithm commonly used with two-factor authentication (2FA).  How exactly, does this algorithm work, and how can we make it work with JavaScript?

Using the following resources as our framework, we can make use of the TOTP algorithm quickly and easily:

  • http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/
  • https://code.google.com/p/google-authenticator/source/browse/libpam/totp.html?r=a852f172b62bf58d436e942e59f6439224b1477d

For TOTP to work, we are going to need to make use of an HMAC function.  JavaScript doesn’t natively have one, but lucky for us there is a great open source library called jsSHA that we can use.

A little background on two-factor authentication and time-based one-time passwords in general.  Two-factor authentication is an extra layer of security that many web services offer.  You enter your normal username and password followed by a six digit code that changes every thirty seconds.  This six digit code is determined based on a secret key that both you and the web service share.  The code changes based on the machines system time so it is important the web service and device have accurate times configured.

A complete and working version of my code can be seen below:

The above TOTP code can be used like the following:

Don’t forget that you will need to include these libraries in your HTML file like so:

Just like that, you now have a perfectly capable way to generate six digit passwords for two-factor services.  You can even use this code, like I did, in your JavaScript based Phonegap or Ionic Framework application.

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

  • [email protected]

    Wondering if you might have any thoughts as to why the IDE is throwing this error?

    Uncaught String of HEX type must be in byte increments (13:08:01:288 | error, javascript)
    at getOTP (public_html/js/TOTP.js:48:19)

    States “HEX” is undefined. I thought the sha.js took care of defining “HEX”?
    Thank you.

    • Just to get me more information and rule things out:

      What IDE are you using?
      Maybe it is a false alarm by your IDE and actually works when you try to run it?

      Let me know.

      Regards,

      • [email protected]

        I’ve tried it in both NetBeans IDE 8.0.2 and Visual Studio 2013. They both give the same error stemming from the “HEX”, Uncaught String of HEX type must be in byte increments. I added some console.logs and debuged using break points and same thing. It’s throwing and error stemming from the sha.js file dealing with “HEX”, deals with “HEX”.

        function B(a) {
        var c = [], b = a.length, g, f; if (0 !== b % 2) throw “String of HEX type must be in byte increments”; for (g = 0; g < b; g += 2) { f = parseInt(a.substr(g, 2), 16); if (isNaN(f)) throw “String of HEX type contains invalid characters”; c[g >>> 3] |= f << 24 – g % 8 * 4 } return {
        value: c,
        binLen: 4 * b
        }

        Do I need to define “HEX” somewhere manually?
        Anyone else get this error?

        Thanks much for the response.

        • Can you share with me the string that you are trying to pass in that is causing errors? I’m wondering if you’re using special characters.

          • [email protected]

            Using the code above, except I substituted “bigcow” for “SECRET_HERE”

            I have sha.js and TOTP.js as the src in the html. And am calling the following JavaScript code in a script tag in index.html. It throws the same error when I keep “SECRET_HERE” rather than replacing it with a different string.

            var totpObj = new TOTP();
            var otp = totpObj.getOTP(“bigcow”);

            Seems like it should be fairly straight forward, wondering if I’m doing something incorrectly. Currently I’m running the index.html with the two JavaScript files it calls.

          • The string you chose is not valid for converting to hexadecimal. However if you were to choose “bigcov” that should work fine. Websites that generate these secret keys should know the rules and you should be fine. I’ve personally not had an issue with a TOTP secret key.

            http://en.wikipedia.org/wiki/Base32

            Characters 0-9 and A-V make up a valid base 32 string that can be converted to hex.

            Let me know if that makes sense.

            Regards,

          • Vasu Modekurti

            I tried with ‘bigcov’ and I still see the same issue. Can you please check

          • When I tried, it worked for me.

          • Rhonan Carneiro

            I think the problem is the sha.js version. I’ve tried with the current release of sha.js and I got a error, after I changed to 1.6 (https://raw.githubusercontent.com/Caligatio/jsSHA/v1.6.0/src/sha.js) it didn’t work with “bigcov”, however it did work with “JBSWY3DPEHPK3PXZ”.

  • Nathan G

    Interested in TOTP i think your code is usefull and dangerous all at once.

    Effectively doing TOTP on the client side seems a nonsense, i’ll try to explain myself.

    Your secret must be secret and so must not go anywhere in the source code you send to the client. To be good your secret should be different for each users ideally a random generated key associated with user account. The only way i see your usage don’t exposing the secret in the code is to use a secret entered by the user. So the only secret i can imagine to use client side is it’s account password. Using the password as a secret for TOTP won’t bring more security over basic password, it will eventually be weaker than traditional password authentication.

    So i’m really wondering what you can use as the secret on the client side. I probably lack some understanding that i’ll be glad to acquire or maybe your implementation should be modified for real world usage.

    • Valid points.

      I recommend you encrypt the TOTP secret before storing. Forge is a great library for doing this.

      The whole purpose is to be able to generate a time-based password using the same methods locally as remotely. This way you and the remote service provider can compare codes to validate identity. The other point behind 2FA is that if someone guesses your account password, they’re still going to need this extra TOTP password. TOTP passwords should be stored on a device that the malicious user won’t have physical access to and maybe even with encrypted storage. With this, TOTP brings way more security over a basic password, encrypted or not.

      Regards,

  • SpencerLawrenceBrown

    how did you sync the time between your app and your server?

    • I did not. Syncing the time between application and server would be taking this tutorial to the next level. However, I don’t believe apps like Google Authenticator do this.

      As long as both the server and device are getting their time from the internet, you shouldn’t run into any issues.

      Regards,

  • I’ve got a live demo for a similar mechanism, but I ended up using forge.js. It’s a little bloated so I’ve though about using jssha. However, forge does have a secure CPRNG (based on mouse and key events rather than Math.random()) which is useful for client-side key generation.

    The browser demo is at https://daplie.github.io/browser-authenticator and I’ve also got complementary server code up: Node Authenticator (https://github.com/Daplie/node-authenticator).

    • Thanks for sharing 🙂

      Forge is a great library that I use for other things.

    • parthiban L

      Hi AJ its really cool, m a beginner and interested to use dis in my sample project. can u pls share the code and help me?

  • GhostJohnny

    Hi Nic,

    Could you show how to implement it in an ionic app?
    I have created an otp.js file which I’ve added as a src=”js/otp.js”, but the thing is I already have a generated qr code which I scan with the ionic app (camera) and I get an encrypted code. Now I just need the OTP function to unencrypt this code with a pin code that I already know. Not sure where to start thou?

  • Giridhara Madhavan

    I keep getting the exception String of HEX type must be in byte increments. What do I do ?

  • luv sehgal

    i am not able to run into html file and in server to , i have created three files one is topt.js and one is sha.js and one file is for html and i am not able to run .help me please to sort out this problem

  • Martin Thorpe

    What version of jsSHA did you use for this demo?

    The latest version has a different way to construct the hex and the hmac.

    I think it returns data in a different format. We have a similiar piece of code in house but using the new jsSHA libs do not produce a valid OTP.

  • Martin Thorpe

    This is interestingly what I get from your code using version 2.2.0 of jsSHA:

    Chosen SHA variant is not supported