Some of this is good advice, but there's a BIG point on the 'Password Storage Cheatsheet' that's linked and referenced by the above article, that I don't think is solid.
https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet...

Specifically, it suggests storing passwords using: `return [salt] + HMAC-SHA-256([key], [salt] + [credential]);`

It goes on to note that the key must be protected as private, strongly random, and stored outside the credential store, while the salt (can we please call it a nonce?) can be safely stored against credentials.

I'm still not comfortable with this construction. Stick with their earlier advice and use scrypt, bcrypt, or PBKDF2. That's my order of preference too, which differs from theirs somewhat, but that's a minor quibble; all three are reasonable.

The problem with their construction is that HMAC-SHA-256() is designed to be fast, and so attackers have the opportunity to make a lot of guesses quickly. The secrecy of the key helps over a straight SH256(...), but not a lot for the following reasons:

1 - It assumes an attacker who compromises the credential store won't also have the key.

2 - It assumes an attacker is unable to recover the key.

1) is a valid assumption for certain classes of attack. If your key is stored in an environment variable or something, while credentials are stored in a database, an attacker who compromises your database via a SQL injection won't have the key. But the problem is that an attacker who compromises the application may. If I have full remote code execution on the server (and you have a bad day then, passwords aside) I'll have the key. Or maybe an attacker has an arbitrary file read (not quite as bad a day), and you store your key in a flat file on disk. Or an attacker can cause your application to generate a stack trace (disclosing runtime details) and view the key...

You get the idea - there's lots of potential ways to get that key regardless how you store it, and everything hinges on that. Once they have the key, they can mount dictionary or brute force attacks against credentials just as they would against `SHA256([salt]+[credential])`

2) is a valid assumption only if the attacker doesn't know a single password's plaintext value and the key is sufficiently long and random. If I know the password to my own account (and I likely do) or any other account (let's say one user on the site uses a password that was recovered in another breach) this scheme fails.

Suppose my salt is "SALTYSALT" (okay, so my PRNG sucks; also a detail to be wary of) and my password is ye olde "PASSWORD" (yah, this sucks too.. but it's my crappy password. Maybe I added it just to observe the resulting HMAC value?) Now I can just try calculating `HMAC-SHA-256("A", "SALYTSALT" + "PASSWORD")` If that doesn't match, try `HMAC-SHA-256("B", "SALYTSALT" + "PASSWORD") and so on. The one thing I don't really know that would help is the length of the key. If it's long enough (We'd want at least 256 bits), and strongly random, I may have a difficult time. It it's short (And they make no recommendation on it's length, just that you "Generate the key using cryptographically-strong pseudo-random data"), I'm going to crack the key, and then I'm back to attacking all the other credentials.

I MIGHT be convinced of this being reasonable if it can be ensured that all the HMAC calculations are done in something like an HSA or TPM which generates a large key internally and doesn't expose it, even to the application. But that's probably not the scenario we're talking about here. Even then, you've got nothing to lose by using an adaptive algorithm rather than the HMAC construct. For anything else, it's far safer (and easier really!) to use scrypt, bcrypt, or PBKDF2. So just do that.