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 a key just 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 an as such I wouldn't like to use them
- Emails do not at least most of them offer end-to-end encryption (plus they are mostly stored at 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 and etc...
Both of the above problems are already solved for you if you use the browser as your medium. End to end encryption is provides by the
HTTPS protocol and you have authenticated the user with whatever method you deem acceptable. Plus you don't have to relay in third party entities security polices (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 access the attacker can't gain access. This however is not as user-friendly. As I said above to much security can be bad.
As far as your concerns about generating a new key for HOTP every time remember.
Also the key should be shared with the user only one time and never again
When a new key is the old must no longer work and ass a result HOTP code that is generated with the old key should be invalid. Also, 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 users.