Sending Magic Links with Nodejs
3 min read ·
The most popular method of logging in to an application is by providing a username and a password, but that may come with some cons for users. Even though there are many password managers it takes time to use them. Not much but still. And not everyone uses them. Some apps have frustrating and complex password rules, so coming up with a new password may be a tough task. The passwordless system makes quite a good alternative to the common login and password authentication. It is used by, among others, Slack and FramerX as a magic link that is sent to the user to enable his authentication in the app. The flow in a passwordless system goes that way:
-
The user visits the app, where is a form for an email address
-
The user provides an email address and clicks some confirm button
-
The magic login link is sent to the user email
-
User clicks the link and is redirected to the app, already logged in
And after that, the magic link is no longer valid.
Steps below will cover some basic setup for implementing passwordless flow in NodeJS.
Create an express app
First, we need to create a simple express app and add some endpoints. The code below is a setup for an express server with helpers for parsing incoming request, logging and enabling cors. We need to add two routes that later on we attach handlers to. They are /login and /account . The first one will be responsible for sending magic links to users and the second one for authenticating the users.
Setup nodemailer
We’ll be using nodemailer for sending emails, but first, we need to setup it. There are some things needed: email address, email password, SMTP server host and SMTP server port. We also need some email template that we’ll be sending to the users along with the magic link. The template may be a simple string or a html snippet.
Generate tokens
For this, we’ll be using jsonwebtoken package that will basically do everything for us. Our token will consist of just two properties: email and expiration time.
Sending an email
Now we need to add a login handler where we first validate a request to check if it contains a user email, then we generate a new token for this particular user and finally use transporter that was set up above to send an email.
User authentication
Having logged user we need to authorize his/her requests to our server. What exactly we need to do is:
-
Check if there is authorization header in the request
-
Verify if the authorization header is a bearer token
-
Try to decode this token
-
Check if the token has all the required fields, which in our case are: email and expiration
-
Compare expiration date and time to the current to assure that token hasn’t expired
-
Finally, verify if there exists a user with the email as extracted from the token
Conclusion
I’ve presented basic setup for passwordless login on top of the normal auth flow. The biggest benefit I see is the fact that if users can get into some product faster and easier, they’ll be more satisfied.
On the other hand, even that it may be easier to get into a product than in the standard login password systems, it may be harder to come back to it. Every time the user wants to log in, he needs to wait for an email, check an inbox and click the link. It may become frustrating, so if there are short session timeout periods or the app expects users to log in frequently the passwordless flow may not be the best choice.