What are Magic Links?
Magic links also known as temporary links are links that enable one time action through SMS or email without logging into the actual system through traditional means.
You can use magic or temporary links to:
- reset a user's password
- one time access to a website or application such as slack or medium
- actually login into an application without the need of manually inputting your username and password
- offer discounts in eCommerce systems
Why am I implementing?
At work, as we are using an in house framework, one such user requirement is to implement Magic links. The use case scenario is as follows:
Consider Bob who is an admin in a MIS, while Alice is a regular user who has forgotten her password.
Bob opens the list of user and click on the reset password feature for Alice. The latter receives a mail with a temporary link valid for only 24 hours.
She opens the link which points to a page related to the MIS. She enters her new password and confirms it. Once done, she is redirected to the login screen. She enters her new credentials and is successfully logged in the system.
How to built the dynamic route?
For the backend, I am using ExpressJS and for the front, VueJS. I first make sure that I have an outside page or route for example - /reset-user-password - that is separate from the login. Each page checks if the VueX Store contains the user token based on Token Based Authentication (instead of cookies). If not, they are redirected to the login page.
The idea is to pass a random unique string though this URL using query object such as reset-user-password?t=randomUniqueStringHere. This is what the API shall send in the email as a link. Once Alice opens the link, another API call is done to decode the t query and randomUniqueStringHere value. With ExpressJS, you can easily do this by using req.query.t.
Ways to implement
There are two ways to implement the reset password magic link encoding and decoding feature:
- Non persistent
The persistent means we are going to store some data in the database while the other means, we don't store any day.
You can use additional columns in your User table to add for example, link_reset_password_temporary (string) and link_reset_password_expire (datetime).
The idea is you generate a random unique flow of characters and store in the database with the current date time using libraries such as NodeJS Crypto or UUID. When the user clicks on the link - you have an API request function that will retrieve - the user based on the unique string. You then check if the expire property of the resulting result is within the allocated time, in my example, 24 hours. Once validated, you remove these two fields.
In my project, I am already using JSON Web Tokens (JWT) for Token Based Authentication. So when Bob clicks on send password, I use JWT to send an encryption of the id of the user whose password is going to be changed. I also use the built in expiresIn property.
I retrieve the Front End Url, which is stored as Environment Variables (ENV), concatenate as a query parameter in the url before sending as a link through mail.
Once Alice clicks on the link, her browser opens it. In this route, there is another API request to decode the link passed. If invalid, for instance, there is no query parameter, it returns an error. Otherwise, if the token is still valid and not yet expired, the id of the user is returned to the front. When Alice changes her password, the application passes the id and the new password to the API which resets it successfully.
She is then redirected to the login page where she can put her new credentials.