How to create expiration date logic for a link shared via email - node.js

I am sending a transaction ID as a link via email, using this link anyone can search for the details of transaction happened in my system. I would like to enforce expiry time for the link, say for 1 month link should work and post 1 month, link should expire.
I am using nodejs for implementing my software. I would like to send only transaction ID as the parameter for creating the link.
I planned to combine Transaction ID and expiry_timestamp and encode/encrypt and send the encoded/encrypted data as the parameter in the URL. Later when link is clicked and request is received to server, I should be able to retrieve the expiry_timestamp and compare it with current data and decide to proceed or no. Here if Iam sending timestamp in plaintext, user may change the timestamp and request, so I am planning to encode or encrypt it.
Please suggest some cryptographic techniques for implementing this.
Thanks in advance.

You can do this by following way.
Create another column name something like token
Store expiry date and time on another column as you are already doing this.
Pass token as a query string that has been stored in DB rather than the timestamp.
when user click on the link you can check either validate or not using token (query string)
You can use this( https://www.npmjs.com/package/rand-token) package to generate tokens.

Related

How to generate one time url to get a feedback in nodejs

I am developing an app for traveling agents in an insurance company with MEAN stack. When a traveling agent is done with the customer, a unique URL must be emailed to the customer to get feedback. How can I generate that unique one-time URL? Or is there any other way to achieve this without creating an account for the customer? (like sending a responsive email to the customer and get feedback)
One way you could do this is to 'encrypt' the query string. So lets say you want this to be a 'one-time' URL.
On your node server, you generate a one time string like customerID=12343&timestap=time&action=something
Next, on the server you would run the string through an encryption algo to encrypt the string so after it may look something like sd8753454sd548787e54sd54SDe85432 <--(this is not valid just an example but would be unreadable)
Now, the email you send out with the link would be something like https://example.com/validate/sd8753454sd548787e54sd54SDe85432
The validate route will require the string, grab that and then 'decrypt' the string. You should now have the valid string customerID=12343&timestap=time&action=something, so your DB updates etc and flag in the DB that it was clicked OR use the timestamp to check if the URL is expired
This is just one way, and when talking about encryption and how strong you need it is a huge topic, this is just one method of many ways.

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.

How to generate login code with expiration in Nodejs?

I'm setting up a website using Node.js Express and MongoDB that allow user register and login and it's work nice and no issue with it. But now i want to generate multiple login code (something like a coupon code) with an expiration date so user can only use it once. and if the login code expired, user cannot login anymore. Is there a way to do that?
I was looking authentication strategy on passportjs but i cannot find any of it.
Thank you
For setting this up with mongo with a schema like { createdAt: timestamp, code: string }
Create a unique index on code so that you can't create the same code twice. In client-side code, you'll end up needing to retry creating some codes. (You could instead pre-generate codes & put them into a queue and pull them off, but that sounds a little bit more complicated)
Add a TTL index on createdAt for expiration to automatically remove the documents. If you instead want to "expire" the documents but track that the code used to exist, you'd need to manually check the timestamp.
When a code is used, you'll want to delete it (or mark it as used).
You'll likely want to include some sort of rate-limiting by ip so that people can't brute force codes.
With passport, you'll want to specify a "custom" strategy. With a custom strategy, you can do anything you'd like to set up authentication. Passport-js How to create a custom strategy has a little bit of guidance.

Node express public accessible url security

Good day everyone.
I would just like to run this scenario past you to ensure that I don't have any gaping holes in my approach.
What I want to achieve.
1.Send a mail to a client with a url + parameter that can uniquely identify the client when he clicks on the url and the parameter gets sent to my express server.
2.My express app receives the parameter and decodes it to retrieve the parameter from the encoded string so that I can do a lookup of the customer.
My approach
1.When sending the mail I generate a base64 encoded string that uses the customer_id + '~' + customer_name as the url parameter on the mail I send out.
I also url encode the string.
2.When the user clicks the url and the request gets to my express server I decode the string to retrieve the customer details (customer_id and customer_name) then do a lookup for the customer.
The information I'm displaying is semi sensitive so I don't want anybody tampering with the url to see another client information.
Is my approach correct?
Thank you guys!
This is not that secure. Since you mentioned you are concatenating customer ID + name and just converting to base64, a knowledgeable user could simply decode it and then try variations to "potentially" access other users records.
As a general rule of thumb is not to pass any customer info as link parameter if its sensitive. Instead, create a UUID and store in against the customer record. I personally even set TTL on this UUID. Its a bit more harder to guess and a bit more secure. Then pass that as the link's parameter which could be used for lookup and further processing.
Hope this helps!
While the original approach is not secure, using MongoDB's ID's is not secure either. See this related question.
Unfortunately, MongoDB ID's are guessable, as they were not designed to be used as a source of entropy.
But it really depends on the value of what you are protecting with these URL's, and how much you are willing to compromise security for the sake of convenience. MongoDB ID's are certainly better than the original approach, and may be secure enough for you to be willing to accept the risk.
But if I saw that in your application while performing a security audit, I would mark it as a weakness and recommend that you use a Cryptographically Secure Psuedo-Random Number Generator ( CSPRNG ) such as /dev/urandom.

Nodejs: How do you differentiate between users?

I am new to backend. Only way i can think of is this:
at visit if doesn't have cookie then do next step
generate unique id and then set it as cookie
then upon every request check if that id is present in database and if not go to step 1.
if it's present then fetch data under that id and respond as needed.
Now is it safe?, Is it logical. What does actually happen.
Scenario to use in:
This is meant for not logged in users. Basically, users visit my site, click something that takes time.. so user is redirected to a page with waiting gif all the while using ajax (long polling) server is requested for results. Now to differentiate between requests from multiple users i am thinking this will work. It's important because data i'm going to be sending back is going to be private from 3rd party.
You have to decide up front if you want a:
Temporary session for a given browser that will only work for that user in one specific browser and may be reset at any time
or
A longer term session associated with a particular user that they user can use any time and from any browser.
The first can be done with a server or client generated cookie that is any globally unique value. You can then use that id as a key into your database to get the user's server-side settings/data on any given request. In node.js, there are a number of session related NPM modules that will handle the generation of a sessionID for you automatically. The problem with this first method is that it relies on the preservation of a cookie value in the user's browser. Not only can cookies be temporal (they can be cleared), but they are only set in one specific browser.
If you're only planning on using it for the duration of one session, then this first method should work just fine. It is common to use a time value (e.g. Date.now()) combined with a random number for a unique id. Since no two requests can be processed in the same ms, this guarantees a unique id value. Add the random number to make it not be predictable. Other NPM session modules offer further features such as an encryption key, etc...
The second method requires some sort of identifier that the user must enter in order to know which user it is (often an email address). If you don't want other people to be able to impersonate a user by only knowing their user id, then you also need to require a password. This essentially requires a sign-up process on your site where the user ends up with a userID and password that they use to login to your site.
It is not uncommon to see the first method used for short term storage on behalf of the user. For example, a shopping cart on a site that you are not registered for.
The second method is used by all the sites that have a user login.

Resources