I'm trying to find a good algorithm for generating authorization codes, access tokens and refresh tokens in an API.

Currently, I am looking into the following setup:

Tokens are generated using the RNGCryptoServiceProvider class in C#. (I have limited the allowed chars to the following set: abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!@$?_-)

Authorization codes are generated with 256-bit length and have a lifetime of 5 minutes. Access tokens are generated with 512-bit length and have a lifetime of 1 hour. Refresh tokens are generated with 2048-bit length and have a lifetime of 60 days.

Those codes and tokens are then salted with a random 64-bit salt, and then hashed using SHA-256 before being stored in the database.

Considering the token lifetime, salt and hashing algorithm used, would this be a reasonable secure setup?

  • $\begingroup$ You don't need to go beyond the 256-bit length. 256-bit length is already considered secure for centuries. $\endgroup$ – SEJPM Oct 29 '15 at 12:18
  • $\begingroup$ Do you mean using SHA-256 is enough, or the random token is enough with 256 bit length? (Or both?) :-) Can I drop the salting since the token is random anyway? $\endgroup$ – azzlack Oct 29 '15 at 12:38
  • 1
    $\begingroup$ SHA-256 is OK, the tokens may be increased to 384-bit in size (considering you only have 6 bits of entropy per byte) anything beyond is pure overkill (even 256-bit length would be OK with 192-bit security). And you don't need to salt as your strings are high-entropy and salting is the counter-measure to fast low-entropy guessing. $\endgroup$ – SEJPM Oct 29 '15 at 12:45
  • $\begingroup$ @SEJPM Looks like you’ve got yourself an answer there. (Just saying…) $\endgroup$ – e-sushi Oct 29 '15 at 16:11
  • $\begingroup$ Completely agree, but how do I mark a comment as answer? $\endgroup$ – azzlack Oct 29 '15 at 16:19

Your setup is secure. However it is largely "unneccessarily" secure.

First the generation method: You're using the RNG-CSP which is (I guess) Microsoft's software interface to the Windows secure PRNG, so this is fine.

Now for your tokens:
You're restricting the character set, which reduces the possible entropy per byte, but is fine if you're in a Web-Context. Note that you "only" have about 6 bits of entropy per byte (8 bits).
Your tokens are however too large. The standard security levels are 128, 192 and 256 bit security with 256 being considered secure as long as we're stuck in our solar system and don't discover any fancy energy source except our sun. Your current token sizes provide 192, 384 and 1536 bit security which is unneccessarily large in the latter two cases. I'd suggest changing the token's lengths to 384 bit. If you want, you can keep your short-time tokens at 256 bit or you can also raise the size if you feel 192-bit security (secure for a few decades at least) isn't enough.

Your choice of the hash is fine, SHA-256 provides 256 bit pre-image resistance which is just what you seem to want. Larger hash functions may be an option for you if you want to have more than 128-bit security against quantum computers, which would require you to use SHA(-3)-512

TL;DR: The long tokens may be shortened to 384 / 256 bit length, the rest is fine.


While SEJPM answered your question quite directly, please consider using stateless tokens instead. A token would be of the form identity_data||expiration_date, encrypted and authenticated using AES-GCM or perhaps ChaCha20-Poly1305. Your token is the nonce and cipher text concatenated and base64 encoded. Such a scheme prevents you from having to make a database query on every request, and prevents having to worry about replicating your session store database for high availability. All you need to do is distribute the key used for this token encryption to each server. The clients themselves act as your "token database", and your architecture is vastly simplified.

  • $\begingroup$ Is there any documentation or OWASP recommendation for exactly this approach? $\endgroup$ – danieltalsky Oct 21 '18 at 17:36
  • $\begingroup$ JWT is the most widely used standard for stateless claims tokens. Beware however: JWT has too many options. You should only use the HMAC-SHA256 option, as the others are insecure, including the way they use RSA in JWT. $\endgroup$ – rmalayter Oct 23 '18 at 19:35
  • $\begingroup$ Yeah, I've heard many serious criticisms of the JWT approach. Using HMAC-SHA256 for JWT is considered secure however? $\endgroup$ – danieltalsky Oct 25 '18 at 21:28
  • $\begingroup$ So long as the library your using for JWT validates that only HMAC-SHA256 is in use. Even then, good old fashioned session tokens stored in the DB or app server RAM are simpler and more secure for most applications without high scalability. You’re typically hitting the DB anyway on every client request. $\endgroup$ – rmalayter Oct 25 '18 at 22:19

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.