Account verification emails with links vs codes

The overall goal is to verify that a user can be reached through the email address.

This is done by creating a token, and any way of delivering that token back to your server will do, whether it is having the user click a link or copy/paste (or retype) a code.

Since your list includes password resets and email resets as reasons why you might send a token, keep in mind that these have additional concerns beyond simply verifying that an email will reach the user. Attackers may try to guess the tokens.

Longer tokens may be more difficult for an attacker to guess, but users may be less willing to type them.

On the other hand, usability always plays a role in security. The best security isn't the strictest; it's the security that people will use, and especially that they won't seek workarounds for.

People who are security conscious are increasingly less willing to follow links in emails. People who are habituated to following links in emails are also more likely to follow phishing links in malicious emails.

In addition, users may not have access to their mailbox with the computer that they're using, or may not be using the same web browser that their email client opens by default. I.e., the default email clients on mobile devices may open the default browser that comes with the phone/table, rather than a browser that the user installed later and uses regularly.

Thus, for a simple email verification, or for a second factor during login, short codes that a user types are good enough, so long as they're generated using a cryptographically secure pseudorandom number generator (CSPRNG) seeded by a high entropy source, such as /dev/urandom or a similar system on your platform. You can also include a link that will have that code, in case this is easier to use by the user, rather than copying and pasting the code. The key here is that, for something that is common (i.e., daily), make it as easy as possible for the user to increase their security.

If the user is trying to change something about their account's security, though, such as changing their password, changing their contact information (email address), or changing any part of their 2nd factors (also in your case, email address), you should make the token longer, to the point where it doesn't make sense to have users type it in. Still use your high entropy source to seed your CSPRNG, of course.

In all cases, these tokens should have a very limited life, up to a few hours. Make them single-use only (so that a user can tell that someone used their token first or, if the eavesdropper is slow, the eavesdropper can't reuse that token), and make the token usable only by that one account. (There are stories of people generating password reset tokens for themselves, then changing the user ID to someone else's, gaining access to their account that way.) All login and password reset attempts should be throttled both by IP and by account, and failed attempts should be logged.