Ensuring client IDs are unique
rand = crypto.randomBytes(32).toString("base64");
id = hashFct(rand).substr(0, 8);


If those random bytes are random, passing them through a hash function adds nothing. If they are only somewhat random, hash + truncation is better than just truncation. However, crypto.randomBytes are from a strong RNG, so you can use them as is.

The problem is that 8 bytes is not always unique. You solve it by looping until you get one that is unique. However an attacker could do the inverse: guess until it hits a real ID.

The probablity of guessing a particular ID is \$2^{-b}\$, where b is the number of bits in the random number. If you have n users in your database the probability is n times as high. With \$n = 2^m\$, the attacker needs only about \$2^{b-m}\$ guesses to hit some ID.

If your ID's are 8 bytes:

2^64 bit IDs (8 bytes)
2^20 users   (~1 million)
//
2^44 guesses (~17 million million)


However, if your IDs are 8 characters in base64:

2^48 bit IDs (8 base64 characters)
2^20 users   (~1 million)
//
2^28 guesses (~268 million)


Depending on your application and the number of users it is possible that both, the latter or neither is insecure.



My recommendation (echoing well known advice) is to use the 32-byte random string directly as an ID (converted to base64 if needed). That gives such a small chance of collisions that you can do away with the loop as well. (It's likelier e.g. that the CPU fails to loop due to cosmic rays than that you see a collision.)