Is single iteration SHA-256 safe enough for hashing 128bit random number API keys?

TLDR: Real passwords have often low entropy. To prevent brute-forcing of such passwords, hash algorithm should be resource expensive.

I find you question very good. Many developers when talking about password say "of course, use Argon2 or similar expensive hashing". But not many of them think why it makes sense to do it. The answer is not obvious.

If all of your users have passwords with 128 or more bits entropy, then yes, a single iteration of SHA-256 is sufficient. To get such entropy, you may need for instance to use random number generator. A human readable representation of such password (say base 64) will consist of more than 20 characters. How many of your users do really use such passwords?

In the reality many users use passwords that are based on the words of their language with may be 1 digit and 1 special character. Often such passwords have only 50-60 bits of entropy. Fast hashing makes brute-forcing of such passwords realistic.

To make brute-forcing much more slow and expensive, hash algorithm should consume more CPU and RAM resources. I will not explain it here in more details, as I understand you know that well.


You are correct in saying that the size and randomness of an API key negates the use of a password hashing function. 128 bits generated by a CSPRNG should be fine to store with a single SHA-256 hash.

The biggest problem with API keys is different from passwords since they are not reused across sites and cannot easily be brute forced. Usually the biggest problem is leaking the keys from the client applications themselves (or the protocol).

Here are a number of things to watch out for, only the 2nd relates to the key size:

  1. show the key only once at generation time (easy, you've already decided you're not storing it in plaintext)
  2. have a way for users to identify API keys. This could be by showing the first (or last) X characters. This means you need to store these X characters and might want to consider those visible bits as "known" by an attacker
  3. have various scopes (permissions) you can attach to an API key to limit the damage of one key being leaked. Discourage (or disallow) the use of "do everything" scopes
  4. rate limit requests using the same key and attempt to rate-limit wrong key uses by IP address (that gets tricky but it's a reasonably easy step to take)
  5. transmission of API keys is tricky with many options when going over https, choose carefully (and of course TLS is required)

PS: with all that said, you can easily go with 256 bit keys and a more compact encoding than hexadecimal if you're concerned about length. eg: 256 bits in base64 is 43 characters.