4

Tutorials I've come across about implementing magic link authentication (in Node) recommend a mechanism like this:

  1. the user hits your endpoint with their email address
  2. you generate a signed JWT from the email and the date using a constant key (if you are a bit more savvy, you use the asymmetric RS256 scheme instead of the symmetric HS256 used in most tutorials (being the default I think))
  3. send the email with the token as a query parameter
  4. user clicks, endpoint gets hit, you verify the JWT, then the email and the date inside

Apologies for the possibly very small brain question, but why do we actually need hashing or encryption here?

  1. Would it not be more prudent to just generate a large (like 50 chars), unique, random, alphanumeric string (let's call it LURA) then store it, the email and the date and send it to the user? When the verification endpoints get hit, we can say, "yepp, I have that thing on file and I issued it 2 minutes ago, in you go". The purpose of using JWT would be to verify that I was the one who created the token (with my key), but I can also verify that if I just see if I have the LURA string on file, right? Also, JWT has problems. I have a feeling JWT was intended to be used when the machine that's validating it is different then the one issuing it and that its use is detrimental to security in this case.

  2. Bonus question: I've read multiple times regarding encrypting passwords, that SHA256 is way too weak in 2020 and that one should pick Argon2. Why then is RS256 a good choice if it is "to be understood as SHA 256 with RSA 2048 bits keys".

2
  • I cannot reply to your question with an objective answer, but I think JWT is now a days the big thing and is used everywhere. While random string requires nothing, JWT requires secret key that needs to be kept safe
    – Kaymaz
    Oct 8, 2020 at 3:50
  • @Kaymaz Yes, I know it uses a secret, my argument is that JWT should not be used in this case and that its use of a secret is irrelevant. Oct 8, 2020 at 5:39

2 Answers 2

6

Would it not be more prudent to just generate a large ... string

Yes, it would. A token is often a straightforward solution, and is easier to get right. Cryptographic solutions often have pitfalls or need to be implemented totally correct to be secure. Random tokens are more secure because they are simpler.

JWTs are especially useful when having multiple systems: if one system provides the token to access another system, and they don't have access to the same database.

SHA256 is way too weak in 2020

SHA256 is still considered a secure general purpose hash function. The problem is that general purpose hash functions are not suited to encrypt passwords, as they are too fast. Since a normal computer can calculate billions of SHA256 hashes per second, it is possible to crack password using billions of guesses per second.

However, in JWT, SHA256 is not used for passwords but for integrity of the message, so there it is not a problem that it's fast. There's nothing to guess.

4

It's true that you can use a random string for the magic link and it'll work just fine. However there are a few benefits for choosing to implement it using JWTs:

  1. JWT validation doesn't require a call to the database. This is perhaps the main benefit of using JWTs at all. Depending on the number of users this can mean a significant performance difference.
  2. It is easier to integrate with existing login mechanisms such as identity providers (possibly 3rd party) that already handle creating/verifying/storing tokens. This is useful for example if your application is already using tokens for logging in users with the traditional username/password combination and want to add magic links as an additional option.

As for your question on the algorithms, for RS256/HS256 in JWT the purpose is not for encryption but for signing. The requirements on the algorithm for secure encryption and signing are different (and even more different if talking about password hashing).

As an additional note the reason to choose between RS256 and HS256 is whether or not you intend to allow others to verify your token.

For RS256 you create a public/private key pair. You generate the signature using the private key while a third party can verify a token you created using your public key. For HS256 the key for signing and verifying is the same so normally you keep it secret meaning only you can verify the token.

6
  • It does not require database calls to validate, true. But that also means that the "token" cannot be revoked. If it the "token" was stored in the database, it would be possible to revoke it
    – Kaymaz
    Oct 8, 2020 at 6:53
  • Speaking about performance to verify a token (in this particular case for login) in 2020 is not reason to use JWT. What makes you thing a call the a database is slower than decrypting +verifiying a JWT? Yes, I am a bit against the use of JWT everywhere :)
    – Kaymaz
    Oct 8, 2020 at 6:58
  • @Kaymaz Yes its a problem of JWTs. In the end you'd have to take a look if the benefits apply to you or not and choose sensibly for your case; I don't recommend JWTs everywhere either. Though I do think there is still a noticeable performance difference even in 2020 if you have a large user base.
    – AlphaD
    Oct 8, 2020 at 7:07
  • Thanks, @AlphaD. If the biggest reason to use JWT over a "LURA" is to prevent a DB lookup, but it compromises security (the exact thing it should promote) then it doesn't seem like a good deal to me. Granted, performance bottlenecks can be used for a DOS, but a db lookup might not be worse than token verification, as Kaymaz said. (I have no figures on that). Further, using it to ease the integration with less secure login mechanisms also doesn't seem like a good deal. You can support those independently (if you must), I wouldn't want to make the first party mechanism weaker to do that. Oct 8, 2020 at 7:23
  • 1
    In 2020 you often have massively distributed systems. You still need a shared consistent db. You can validate a JWT locally at the edge in Asia, Europe, America... without a query to a database, which has to be globally distributed! Thats magnitudes faster. If you run a legacy system with a single machine that has PHP and MySQL on it, there is no difference of course.
    – Josef
    Oct 8, 2020 at 13:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .