where is JWT stored - node.js

Where does a JSON web token live? After doing jwt.sign and adding the payload / expiring date, what happens next, where is it stored ? I cant seem to find anything about it.
Thanks in advance.

JWT is not stored anywhere, its very existence contains everything. Its consisted of three parts, first one is hashing method, second one contains all the information you put there and the last one is signature so you can check if the token is valid or not (if you have secret).
This is actually the main reason JWT is so popular and used - as it can carry information through the multiple systems that can be verified by authorized systems.

Related

How to implement expiring to the account activation link?

I am trying to implement expiring to the activation link I send to the user's email when they register a new account.
The link should expire after 24 hours if the user doesn't click on it.
Up until this point I am able to send the link to the user's email upon registration, the link looks like this 'http://localhost:3000/auth/activate/${verificationKey}', everything works smoothly.
But like I said, I want the link to expires after 24 hours and I just don't have any idea of how to do it.
From what I've gathered so far I think one way to do this would be to delete the verificationKey value from my User entity/model after 24 hours, then if the verificationKey value is falsy I need to send another link to the user.
Now my question is, how do I check if a value (in this case user.verification_key) has been generated for over 24 hours?
This is the relevant code to register a new user:
const user = new User();
user.username = username;
user.password = await bcrypt.hash(password, salt);
user.is_verified = false;
user.verification_key = cryptoRandomString({
length: 10,
type: 'url-safe',
});
Some people have suggested to use Redis for this, which I don't know anything about other than it's a in-memory store, and while I'm ok reading more about this tool, I would like to know if there are other ways to do this. I don't know if by installing Redis I would need extra configuration for the server when I host my app, I'd like to avoid that.
Since you already have some database set up, it makes sense to store some verification key and an expiration time for it. You don't need to actually delete that verification key... just need to store when it expires.
Perhaps you have a separate model for RegVerificationKey, with fields key (randomly generated string), expiration (set to a date/time 24 hours after you create it), and userId (the ID of the user this is associated with). Create this key. When you go to activate, just check to see if there is a key associated with the requested user that hasn't expired yet.
Some people have suggested to use Redis for this
No need here, you already have a database you can put data in.
I would like to know if there are other ways to do this
There's an alternative, where you cryptographically sign your URL. Basically, you would store the key and its expiration data in the URL itself, and include some calculated proof that you (the person with the private key) created this URL. When your system receives this URL, it can verify the URL was signed correctly without even having to consult a database. This method can be complicated and probably isn't useful in your case. I'm just mentioning it here as an alternative. Check out JWT for one possible implementation: https://jwt.io/
Recently I was needed to implement this kind of implementation in my web application. So I just followed the below points to achieve it.
1- Create the URL (web link) and append the current date and time along with an encrypted key which you would store in the database as mentioned below.
2- Create a column in the database table (the table where you store any user specific details) to store a randomly generated key which you have encrypted and appended in the URL.
3- When you would receive this URL on server you would check the encrypted date and time in the URL and would decide whether it is still valid depends on your criteria of retaining a link (e.g. 24 hours)
4- Next you would decrypt that key in the URL that you have appended in it at the time of creating it and would match it with what you have stored in the table.
So by implementing above logic you could achieve the desired functionality.
Hope its useful for any one who wants similar type of implementation
I understood that you already found a solution, by storing two fields in the database: one for the key and another one for he expiration timestamp. Everything depends on the use cases and it is definately one way to do it. However I will explain Redis and JWT as a solution in comparison to yours.
Redis is an in-memory datastore (that also allows persistence to disk) as you pointed out and I think the reason why people suggested it is, that you can define an expiration time for a record. Redis will remove that record automatically for you then. Reference: https://redis.io/commands/expire
Redis would take the work off of your shoulders to check if the 24hrs already passed. If you can’t fetch the key anymore, the key probably expired. Another benefit of Redis is, that is super quick compared to your normal database query. But if you only need it for the activation link, which is a one-time-action for the user, the time benefit is negligible. Also you would introduce a new technology just for that use case.
#Brad already suggested using JWT (Json Web Token) instead of implementing your own token solution and I would also suggest that for the following reasons.
A JWT is a self-contained token consisting of three parts: Header, Payload, Signature. The header contains the name of the algorithm that was used to create the token. The paylod contains some standardized fields (e.g. creation date, expiration date, subject the token was issued for like username) and you can also add custom fields. The third part is a signature that ensures that no one changed the payload after it was issued by your token service.
Self-contained means that the token contains everything to validate it, including the expiration timestamp. In your case the expiration time is not part of your token but stored in the database. If you create another microservice that needs to verify your token, that service needs to contact your main service which contains the logic to check the expiration database field.
With JWT the Microservice would only need to know the secret key that was used to sign the token and then you can just import some standard JWT library to verify the token. These libraries validate the signature as well as the expiration timestamp which is an optional field in the payload of the token.
By the way, the payload can be read without knowing the secret key from the signature. So it is even possible to read the payload for example on client side to check the expiration time.
With your solution you have additional database calls, which are potentially slow. For an activation link that is acceptable, but for tokens with recurring use within a short timespan (i.e. API requests that require authentication) additional database calls should be avoided. Also you need to implement token generation and verification yourself, whereas JWT provides standard libraries. This is a benefit when you want to have another Microservice in Java instead of NestJS for example. You can quickly knit them together by using standard libs instead of porting your implemtation or being forced to decide for a centralized token verification service.
One limitation of JWT you have to workaround yourself, is the use case where you want to have a „one time token“. You can only define an expiration date but you can not say that a token can only be used x times. Here you need a centralized service again, which keeps track of how often a token was used (by making use of some datastore) and all other services around need to contact that service.
A good starting point for JWT with NestJS is the official NestJS documentation.

JWT - What is the best way to use jsonwebtoken ? I'm lost

I’m learning to code for one year now. I mainly learned how to deal with a rest API (Node/Express on back-end and Vue on front-end).
I get to the point where I want to develop the ideas I have for app.
For this, I first wanted to develop the backend to have a authentification process that I could use as a boilerplate for other project I would have.
But now I’m completely lost with Jsonwebtoken and how to exactly use it in order to make something secure as well as user-friendly.
So far I understand that a rest API should be stateless (I.e. nothing should be store server-side and should therefore not have DB calls -as for sessions- to grant access to data).
In this respect, I’ve noted different strategies :
Short-lived JWT : (+) this is very secure since you theoretically have to log in every time you want to access the server (-) very bad user experience
Long-lived JWT : (+) user-friendly (persistent login) (-) very insecure (no way to check if JWT was stolen)
Short-lived JWT with Long-lived Refresh Token…
That’s where I get confused…
From every articles/tutorials I’ve read, the refresh token should be linked somehow with a DB (e.g. to store the refresh token key or the blacklisted token…). I’ve also seen a tutorial that partly linked the secret key (to verify the token) with the hashed password stored in the DB. This is kind of smart since previous token will automatically be considered as invalid as of the moment the user changes his password… But this once again mean a DB call…
My point is that I’m coming to the conclusion that
(1) there’s no perfect way to handle authentification process in secure and user-friendly way…
(2) DB calls cannot be avoided to have something a bit secure...
And considering that conclusion, I definitely can’t understand the use of refresh token…
If refresh tokens required DB calls, you could get to the same result with only one main token…
You could for instance store a JWT ID in the token and in the DB… If those two id match upon validation of the token, you issue a new token with a new id that overwrites the previous one… Now if you use an old one, it will never be validated… Then, since you have called the DB to validate the token (most certainly the USER table), you could check in the sametime if, for example, the user is an admin or not (no need to store it in the JWT)… Finally, you could use the « hashed password » trick described above to enhance security…
So… What am I missing ? What is the best strategy ?
I’ll be happy to have your comments on this (or a link to a very good article - I’ve a lot of these though…)
Thank you very much for your help
PS: and I’m not even talking about how to send the token to the server (with cookie but risk of CSRF attach or with header but subject to XSS attack if token is stored client-side)… In this respect I’ve seen multiple tutorial that use JWT through cookie with cerf key stored client side as well as inside the jet => both should be send.
PS2: I hope I'm clear since I'm french-speaking native :-)
So you have asked quite a few questions in this one question. It will be quite difficult for anyone to give a thoughtful answer here, but I shall try. Before that, full disclaimer, that I am the author of a new library called SuperTokens that I believe would provide you the best solution for session management. It's possible that you may have already read our blog: https://hackernoon.com/all-you-need-to-know-about-user-session-security-ee5245e6bdad. It's best if we can chat about this so that I can give you a full detailed explanation about everything you have asked (I would love to help out). Join our discord: https://discord.gg/zVcVeev
Now to answer your question(s):
You should always only use short lived JWTs
Doing a database call for authentication is not a problem, but as everything else, we try and optimise things, so doing fewer db calls, is better. If you go with JWT access tokens and Opaque Refresh tokens, then for most APIs, you do not need to do a db call. However, if you link the secret key of the JWT with the hashed password, then you would have to a db call for every API - which is OK, but I feel unnecessary since you are going to use short lived JWTs anyways (a few hours to a day max)
You mentioned token theft - this is a tricky issue, but according to RFC 6819, you can use the concept of rotating refresh token to detect theft. Of course, actually doing so can be tricky as you have to take care of many race conditions and network failure issues - see https://hackernoon.com/the-best-way-to-securely-manage-user-sessions-91f27eeef460
About why we need refresh tokens: Say you do not have a refresh token, then you would have just one token that you could treat as both, an access and a refresh token. You could still make it short lived (when it's an access token), and then after it expires, treat it as a refresh token - which also has some lifetime. The problem with this is that it's not very clean (point of expiring a token is that it is useless afterwards), and that you are exposing the refresh token over the network every single API call - reducing security. I know you can have HTTPS, but there are HTTPS MITM attacks as well - see the blog post, part 1.
In terms of storage, one neat trick could be to split the access token into two - one to store in secure, httponly cookie, and one to store in localstorage. For every API call, send both to the server (cookies will be sent automatically anyways), and then the server would combine the two and go about authenticating. This would prevent both, CSRF and XSS attacks on sessions!
Now, you could either implement this whole thing on your own, or then use our library that does all these things out of the box: https://github.com/supertokens/supertokens-node-mysql-ref-jwt.
To discuss this more, or any other questions you have, join our discord server.
PS: I know I used this for advertising my lib, but I hope I did answer your question. It is genuinely difficult to give a good explanation to your questions without having a conversation.

What's the correct/standard practice to authenticate a user after registration?

I'm trying to authenticate a user after registration. What's the correct or standard way to go about it?
Using this method as the way to implement it, in step 3, how can I generate the random hash to send to the users email? I see two different options:
crypto
JWT token
I'm currently using JWT for login, so would it make sense to use the same token for user verification? Why or why not, and if not, what's the correct way?
The answer to your question of whether you should use a crypto hash or a token is neither.
The hash you are generating to use as a verification method does not need to be cryptographically secure, it only needs to be a unique verification hash that is not easy to guess.
In the past I have used a v4 UUID with the UUID lib and it works just fine. You could also base64 some known piece of information about the user, like their id or email concatenated with something random, like the time in mircoseconds and a random hex string with substantial length, but honestly the time it takes to build out something like that is wasted when UUID v4 works just fine.
Your hash also doesn't need to be unique (different for each user, yes, but avoid all potential collisions? No) - hitting an endpoint with only the hash is not a great idea. The endpoint should also take an identifier for your user combined with the verification hash. This way, you don't need to worry about the hash being unique in your datastore. Find user by ID, check that verification hashes match, verify. I would only suggest that you obfuscate the user's know information in a way that you can decode on your end (ex: base64 encode their user ID + email + some const string you use).
[EDIT]
Verifying or validating a user is really just asking them to prove that the email address (or phone number) they entered does in fact exist and that it belongs to the user. This is an attempt to make sure the user didn't enter the information incorrectly or that the registration is spam. For this we don't need cryptographic authentication, a simple shared secret is more than enough.
When you store your user's registration data, you generate the shared secret you will use to verify the account. This can be anything that is (relatively) unique and contains enough length and entropy that it is not easy to be guessed. We aren't encoding or encrypting information that will be unpacked later, we are doing a literal string comparison to make sure the secret we provided to the user was echoed back to us intact. This is why a simple one-way hash is OK to use. I suggested a UUID v4 because the components of this hash are generated from random information (other versions of UUID make use of the machine's MAC or the time or other known pieces of information). You can use any method you like as long as it can't be easily decoded or guessed.
After you generate the verification hash you send it to the user (in a nicely formatted URL that they only need to click) in order for them to complete their account registration. URL guidelines are totally up to you, but here are some suggestions:
BAD
/verify/<verification hash>
or
/verify?hash=<verification hash>
With only the verification hash in the URL, you are relying on this value to be globally unique in your datastore. If you can reliably generate unique values that never contain collisions, then it would be OK, but why would you want to worry about that? Don't rely on the verification hash by itself.
GOOD
/users/<id>/verify/<verification hash>
or
/users/<id>?action=verify&hash=<verification hash>
Out of these two examples you can see that the point is to provide two pieces of data, 1. is a way to identify the user, and 2. the verification hash you are checking.
In this process you start by finding the user in your datastore by ID, and then literally compare the secret you generated and stored against the value given in the URL. If the user is found and the verification hashes match, set their account to Active and you're good to go. If the user is found but the hashes don't match... either you provided a malformed URL or someone is trying to brute force your verification. What you do here is up to you, but to be safe you might regenerate the hash and send out a new email and try the process again. This leads very quickly into a black hole about how to prevent spam and misuse of your system, which is a different conversation.
The above URL schemas really only work if your user IDs are safe for public display. As a general rule you should never use your datastore IDs in a URL, especially if they are sequential INTs. There are many options for IDs that you would use in a URL like UUID v1 or HashIDs or any implementation of a short ID.
ALSO
A good way to see how this is done in the wild is to look at the emails you have received from other systems asking you to verify your own email address. Many may use the format:
/account/verify/<very long hash>
In this instance, the "very long hash" is usually generated by a library that either creates a datastore table just for the purpose of account verification (and the hash is stored in that table) or is decoded to reveal a user identifier as well as some sort of verification hash. This string is encoded in a way that is not easily reversible so it can not be guessed or brute forced. This is typically done by encoding the components with some sort of unique salt value for each string.
NOTE - while this method may be the most "secure", I only mention this because it is based on the typical methods used by third-party libs which do not make assumptions about your user data model. You can implement this style if you want, but it would be more work. My answer is focused your intent to do basic verification based on data in your user model.
BONUS
Many verification systems are also time constricted so that the verification URL expires after some period of time. This is easily able to be set up by also storing a future timestamp with your user data that is checked when the verification endpoint is hit and the user is found. What to do when an expired link is clicked is up to you, but the main benefit is to help you more easily clean up dead registrations that you know cannot be verified.

Give a digital signature after friend request to use after to prove friendship in social apps?

I am building some kind of social app with the concept of 'friends' where friends can do actions regarding one or more of their friends,
I would rather not ask the DB if the friendship does exist every time someone sends any kind of request for an action.
An idea I came up with is after a friendship is approved a digital signature will be sent to each user which can be checked in the server for each request which should cost less than asking the db.
Then I can maybe change the async key everyday or so and force the user to ask for a new digital signature in which case I do approach the db to test friendship (it's good for security but also a must if users want to cancel friendships).
What I ask is if this is a terrible idea? Maybe I'm not seeing something. Or just any link to any information about these kind of scenarios would be great.
The idea of handing out a digital signature can be done, though I am not sure if it would actually be any faster then querying the database, seeing as databases are meant to be incredibly fast.
Lets move on with the idea that it is indeed a good idea. You would need a token of sorts that has the information about who is your friends and it has to have been validated by the server. This, to me, seems like something you could use a JSON Webtoken (JWT) for.
Here is the basics on JWTs.
JWTs have three parts to them: Header, payload and signature. The header defines how long the token will be valid for and the payload can contain the list of friends (or IDs of friends). The signature is a hash of the entire thing, signed with the private key of the server, thus verifying that the server has approved this token as valid until time X. The entire thing is encoded before sending.
You would then send the JWT in a HTTP header of some sort, probably the Authorization header. The server could then quickly decode the JWT (there are libraries for this in a lot of languages, JWTs are a pretty good standard) and thus not need to query the database. The size of the JWT does need to be send though, and thus I am not sure you will actually gain any speed from this.

How to make an API call on my server accessible only from one URL

I don't know if the title is clear enough, anyway what I need to do is quite simple: I have some content you can access by an API call on my server; this content is user-related so when you request access to it, you must first wait for the owner to authorize you. Since this content will be probably embedded into blog articles or form posts I want it to be accessible only from the URL the user authorized to.
The only way that came to my mind is to check in some secure way where the request is coming from: the problem with this approach is that anybody could create a fake request, using a valid URL but coming from a non-authorized URL actually.
I'm looking for a way to solve this problem, even if this doesn't involve checking the actual URL but using some other approach or whatever. Feel free to ask any questions if this is not clear enough.
With Sessions:
If you generate a secure token, most languages have libraries to do such a thing, you will have to persist it probably in a session on your server. When you render the page which will access the other content you can add that token to the link/form post/ajax request on the page you wish to be able to access it from.
You would then match that token against the value in the user session if the token doesn't match you return an error of some sort. This solution relies on the security of your session.
Without Sessions:
If you don't have sessions to get around server persistance, you can use a trick that amazon s3 uses for security. You would create something like a json string which gives authorization for the next 30 seconds, 5 minutes, whatever is appropriate. It would need to include a timestamp so that the value changes. You would use a secret key on your sever that you combine with the JSON string to create a hash value.
Your request would have to include the JSON string as one request parameter. You would need to base64 encode it or some other means so that you don't run into special characters not allowed over http. The second parameter would be the output of your hash operation.
When you get the request you would decode the JSON string so it was exactly the same as before and hash it with your secret key. If that value matches the one sent with the request it means those are the two values you sent to the page that ultimately requested the content.
Warnings:
You need to make sure you're using up to date algorithms and properly audited security libraries to do this stuff, do not try to write your own. There may be other ways around this depending on what context this ultimately ends up in but I think it should be relatively secure. Also I'm not a security expert I would consult one if you're dealing with very sensitive information.

Resources