I want to add one-time passwords as gates for certain important actions in the application I am working on. It is not two-factor authentication, although it may be extended to that use case later.

RFC6238 is a very commonly adopted standard for this kind of problem.

It seems very straight-forward to have users download Google Authenticator or something similar on their mobile device and then implement RFC6238 on the server as well.

The one part I can't find any clear guidance on is how to securely share the shared key with users. Is it okay to send this via email or SMS? Is it okay to display a QR code in the browser? Is sharing the secret in the browser defeating the added security, since any logged in user could get a new secret and configure their device to use it to generate OTPs?

2 Answers 2


I would argue that it depends on your specific case. Remember, you need a client that will store the secret key (safely) and generate a TOTP. There are a lot of apps that do that already like Google Authenticator that you mentioned above. You could even create your own (although not recommended). Most TOTP client apps give you 2 options to add a TOTP key: scan QR and insert a key. Although they seem different, they are the same (it's the same key in another format).

So your problem is what medium you should use.

First, I have to point out that it will always depend on the level of security you want to have. Too much security is not always good.

Having said that, I will list my criteria when choosing a channel to transport a secret.

  1. The channel should be end-end encrypted.
    • SMS do not offer such a service, and as such I wouldn't use them.
    • Emails do not (at least most of them) offer end-to-end encryption, plus they are mostly stored as plain text.
  2. The channel should ideally guarantee the end-user identity.
    • SMS suffer a lot from SIM swap attacks.
    • Emails accounts can be easily be taken over if the user is reusing passwords, etc...

Both of the above problems are already solved for you if you use the browser as your medium. End to end encryption is provided by the HTTPS protocol, and you have authenticated the user with whatever method you deem acceptable. Plus you don't have to relay security polices in third party entities (phone companies, email providers).

All in all, I would prefer to use the already existing HTTPS session to transport the secret to the user. If this method doesn't suit you, you can even break the secret into small parts and send then with different mediums. This way even if one of them is compromised, the attacker can't gain access. This however is not as user-friendly. As I said above, too much security can be bad.

As far as your concerns about generating a new key for HOTP every time, remember:

  • The key should be shared with the user only one time and never again.
  • When a new key is created, the old one must no longer work and HOTP codes generated with the old key should be invalid.
  • The process of generating a new HOTP key should be quite thorough to make make sure the one requesting the generation of a new key is the user.

There's really no secure way to do this. At the end of the day it is a shared secret that both your service and the user need plaintext access to. You even need to store that plaintext version on your side because using a derived key isn't a possibility.

This is actually one of the reasons FIDO2 exists. The user must be present to activate this and some malicious code can't do it for you. Additionally, FIDO2 uses private-public key pairs, so it seals the private key away and it is never available for tampering, whereas anyone could steal the plaintext TOTP shared secret and you would never know.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .