28

How secure it is to make JWT as the activation url in email?

For example: Click link to activate your account http://127.0.0.1:8000/account/activate/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw

momokjaaaaa
  • 1,293
  • 3
  • 17
  • 32
  • This particular token is insecure, as your signature secret is very easily guessed. – Thilo Apr 07 '16 at 01:43
  • Also, shouldn't the email address by part of the JWT as well? Or is there some other unique user identifier? Is it "company: Toptal"? – Thilo Apr 07 '16 at 01:46
  • ok that was just an example which I don't even know the decoded data. What if the signature secret is strong? is jwt as a link secure? Mentioned here https://github.com/dwyl/learn-json-web-tokens#q-if-i-put-the-jwt-in-the-url-or-header-is-it-secure really got me confuse. – momokjaaaaa Apr 07 '16 at 01:47
  • let's say email address and unique user identifier is in the jwt – momokjaaaaa Apr 07 '16 at 01:47
  • Related: http://security.stackexchange.com/questions/91348/jwt-for-email-validation-of-an-account – Thilo Apr 07 '16 at 01:56
  • Did you implement this feature? if so, can you explain? I am looking for this for many days – Eniss Mar 20 '18 at 20:26

2 Answers2

24

The FAQ you link to says:

Use-cases for a JWT token in a url are:

Both of these are good candidates for single-use tokens (which expire after they have been clicked).

So, yes. Just make sure that each email can be activated only once (and don't use the terrible "secret" key from your example, if the signature can be faked, then your verification can be bypassed).

Community
  • 1
  • 1
Thilo
  • 257,207
  • 101
  • 511
  • 656
  • I read them and have questions. How can it be secure? can you explain? and how do you invalidate the jwt token once the activation url is clicked/accessed? – momokjaaaaa Apr 07 '16 at 01:51
  • is secure to expose the signature in the email? – momokjaaaaa Apr 07 '16 at 01:52
  • 1
    invalidate the token: Your account database will know that the email has been validated already. So a token cannot be used twice. – Thilo Apr 07 '16 at 01:52
  • secure: it all depends on the fact that no one can fake the token (without getting the email). And that only works if you use a truly secret signature key. But then it does work. You should also expire these tokens (for email activation, an hour should be enough, if not, allow resends). – Thilo Apr 07 '16 at 01:54
  • In the user table, I change 'is_active' to True once the link is accessed. But the token is still valid. The web mention that invalidate token once link is accessed. How can I make the JWT token invalid immediately once link is access? – momokjaaaaa Apr 07 '16 at 01:56
  • The token is not valid if it cannot be used. If you see that `is_active` is already set, then you can reject the token. You must make sure that the same token cannot be used for other actions in your application. Maybe put a claim "action=emailActivation" into the token if you use JWT tokens elsewhere. – Thilo Apr 07 '16 at 01:59
19

Using stateless token like JWT is secure as long as the secret you use to sign the token and the way you verify it are secure. But there are certain additional aspects you should consider before using JWTs as auth-token in your password-reset URI...

As you can't invalidate a specific JWT (without keeping state again) and expiry is not enough (in this specific case), what you basically want to have is your JWT to be what is commonly know a One-time- or Single-Use-Token. The reason for that is that you probably don't want a single password-reset-link to be used more that once to reset a password as it would allow potentially attackers to completely lock-out a user (by continuously changing passwords).

I described how this can work here: Single-Use Tokens w/ JWT - basically you would need to turn some kind of state you have on your server-side (in your case e.g. the hash of the users password) into an HMAC key and use that to sign your user-specific token. This would lead to failing token verification after the password was changed...

jbspeakr
  • 466
  • 3
  • 10
  • 1
    since *you are* using a password from a server's storage, your request is not stateless. For each incomming request you *have to query* your password hash and `turn in into an HMAC key`. You are adding encryption overhead on top of unavoidable db request's overhead. So if you can't avoid making a query in the first place, why not just store a designated id for the password reset token? – Sergey Kolesnik Dec 21 '22 at 17:41