I have a table for single use tokens, and one of the columns is a token_digest which contains a bcrypt hash of the access token. Since the token_digest is a salted and hashed version of the plaintext token, I can't just run a select against the computed hash.

When my application gets the plaintext token from a client, how can I find the correct token record from the database?

The only way I can think of solving this is by adding a prefix to the token that is stored in the database and isn't hashed. So you'd have something like prefix9581d7b867eb0fe0da59fc98faa27fb8. Then you can find the token in the database by issuing a select with where prefix = 'prefix'. Is this incorrect or an insecure solution?


What use case do you have for not having a token ID ?

Anyway if you use long random tokens (having sufficient entropy), then both bcrypt and salt become unnecessary and you can speed up operations by using unsalted SHA2. With the same premise your proposed solution is also acceptable, though it seems unnecessarily complex.

(edited after comments)

  • 1
    Recalculating the salted hash would require the salt first - which is not part of the access token and is also not a value global to all token_digest. Instead the second part of your question is the pointer in the right direction: password hashes are for user-chosen passwords and are designed to prevent brute forcing. If the token is long enough and random from start, then using a password hash is not needed at all, since brute forcing will not work anyway. In this case a simple hash like SHA2 is not only sufficient but actually better since it means less load on the server. – Steffen Ullrich Aug 30 '20 at 6:49
  • @SteffenUllrich salts are stored in the DB alongside hashes. Calculating a salted hash implies fetching the password (edit: the token) from the user and the salt from the DB first. – Enos D'Andrea Aug 30 '20 at 6:58
  • This is about an access token and not about a password. There is no usually no user given together with an access token, i.e. the token is all what is given as authentication information. Thus there is no way to look up the salt for the user. – Steffen Ullrich Aug 30 '20 at 7:01

I recommend that you take a step back and reconsider the use of bcrypt for your use case. brypt and similar functions are designed to address brute forcing of easy to remember passwords. They are deliberately designed to slow down an attacker so that brute forcing gets too costly.They also include a random salt so that precomputed hashes (rainbow tables) get infeasible.

But, an access token is different. There is no need to keep it short and easy to remember. Instead a long randomly generated key can be used. Such a key is resistant against brute forcing and precomputed hashes by design already, so there is no need to address any such weaknesses using a special hash function.

Instead it is sufficient to use a fast and unsalted hash function like SHA-2. This is even the recommended way: bcrypt needs much more computing resources compared to SHA-2 and an attacker might misuse this for a denial of service attack against the server.

And with a simple SHA-2 your problem suddenly vanishes: Simply compute the hash and look up the hashed value in the database. Since no random salt is involved the output of the hash is always the same for the same input.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.