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.
- 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.
- 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.