Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
Over the past years of web development I have stumbled upon the FeathersJS project and have really loved it so far. It offers a lot of functionality out of the box like websockets and authentication which makes it a great alternative to real-time backends like Firebase at a fraction of the cost. There are very little node frameworks that do so much, so well with so little configuration and the only thing I see wrong with it is that it isnât more widely used, so let me start off with why you should use FeathersJS as your API backend framework.
- Scaffolding your application with feathers-cli gives you websockets out of the box with a single line of code.
- Add authentication with a second line of code including all the publicâs favorites like Facebook, Google and GitHub.
- A third line of code connects to almost every single database on the planet. For example MongoDB or all SQL databases.
- Killer integration with Vue and React for real-time updates to your frontend finishes the deal.
With that sales pitch out of the way, wanting to move from prototyping to an actual production scenario, I recently had the requirement to start sending verification emails. There seems to be a module for that named feathers-authentication-management. Going through the documentation for this library was challenging as there is a lot to process at once. There is a tutorial and a repo from Jon Paul Miles, but it seems based on an older version of feathers and has a lot of external dependencies like Pug, Lodash, Mongoose etc. This article is an attempt to write down how to get verification emails working based on the newest version of FeathersJS v3 and without any other dependencies.
The goal of this tutorial is to have a clean feathers app that is able to handle user account creation requests via REST, send the user a validation link and handle the clicking of that link in the simplest way possible. We will implement this one action leaving other actions like password reset, or account changes, for you to implement.
This tutorial will assume that you already have some knowledge of how to use the core of the feathers framework and general web development practices.
All code in this article will be available in the repo: https://github.com/ImreC/feathers-verification-emails
How it all works
What we are going to create is a flow to have the user verify their email address. This goes as follows:
- The user creates an account on the feathers app
- The server adds a field isVerified to the user object in the database and sets it to false
- The server creates a verification token for the user
- The user gets sent an email containing a client link with the token as a parameter
- The user clicks the link and on visiting the client this token gets sent back to the server
- The server sets the isVerified field on the user object to true
- The user gets all the superpowers from your awesome application
So roughly we need to do the following things to get this to work.
- We need to generate a feathers application
- We need to create something to send emails
- We need to install the authentication-management package to generate the token and handle the extra fields on the user object
- We need to create hooks to get it all to work together
- We need to code a simple client to handle the clicked links
- We need to secure some parts of the users service to make sure users communicate via the new authentication management route
So letâs get started.
Step 1: generating a FeathersJS app
To generate our feathers app we will use the feathers-cli package. As a transport we will stick to simple REST because we donât really need anything else for now. We only need a local authentication strategy and we are going to use NeDB as a database for simplicity. We can generate all this with the following lines of code
npm install feathers-cli -gfeathers generate appfeathers generate authentication
We can now create our test user by sending a post request to the users table. Thatâs it, we already have a working app with the possibility to create users and perform authentication. This is what makes FeathersJS awesome.
Step 2: setting up our mailer service
If we are going to send emails to our users we need some way to actually send email to them. Therefore, we need to create a service to send emails from. Unfortunately, at the time of writing this is not possible from feathers-cli. Therefore, we are going to generate a custom service called mailer on the /mailer route.
feathers generate service
This will give us a mailer folder in the services folder which will contain three files, namely mailer.class.js, mailer.hooks.js and mailer.service.js. Since we are not going to use all the methods of this route but only use it for mailing people we can delete the class file.
We then need to install the feathers-mailer and the nodemailer-smtp-transport package.
npm install feathers-mailer nodemailer-smtp-transport --save
I am using Amazon SES to send emails, but any account accepting smtp will do. Jon Paul Miles uses gmail and that also works perfectly fine. To do it with gmail check out his article. Update the mailer.service.js file to look like this.
Then all configuration is done and you can test your new /mailer route by sending a POST request to /mailer with this as body:
{ "from": "YOUR_EMAIL", "to": "YOUR_EMAIL", "subject": "Test", "html": "Test"}
NOTE: both âfromâ and âto â emails need to be verified in Amazon SES for this to work. Check out SES sandbox mode for more details.
Obviously we do not want our mailer to be misused for spam or something, so after testing we are going to close it off by adding a before hook on the all mailer routes. For this we install the feathers-hooks-common package.
npm install feathers-hooks-common --save
And add the following code to mailers.hooks.js.
const { disallow } = require(âfeathers-hooks-commonâ);
module.exports = { before: { all: [ disallow(âexternalâ) ],...
You can test this by re-sending you POST request to see that it now fails, making the mailer for your use only.
Now that we have a simple service that can send email it is time to go to the next step. Setting up authentication management.
Step 3: Setting up the feathers-authentication-management module
Now we are going to set up the feathers-authentication-management module. First letâs install it.
npm install feathers-authentication-management --save
Then we are going to generate a custom service with feathers generate service named authmanagement. We can leave the authentication for now because we are going to do something with that manually later. Also, we can delete the class file from our service again.
Then we are going to create a notifier.js file in the /authmanagement folder. This file consists of three parts.
- The getLink function which generates our token url. This can either have a verify token or a reset token included. For now, we are only using the verify token.
- the sendEmail function which calls our /mailer service internally to send the email
- the notifier function which, based on the action type, decides what email to send where. We are now only using the verification part but this can also be used to code the other actions. Also, we will only be sending the plain link to the email. If you want to use html templates or some preprocessor to generate nicer looking emails, you need to make sure they are inserted as a value in the html key in the email object.
Now all we need to do is set up our authmanagement service to use this notifier function. That looks something like this:
Thatâs it, we are now ready to set up our hooks to tie it all together.
Step 4: Setting up authentication management hooks
Now we are ready to set up some hooks to actually get our service to work. For this we need to adapt the users.hooks.js file. We need to do a couple of things here.
- Import the verification hooks from feathers authentication management by adding this line to the top: const verifyHooks = require(âfeathers-authentication-managementâ).hooks;
- Import our notifier by adding this line: const accountService = require(â../authmanagement/notifierâ);
- Then add verifyHooks.addVerification() to the before create hook to add verification to our user object. This needs to be after the hashPassword() hook. What this code does is that it adds some extra fields to our user objects and generates a token.
NOTE: If you use any ORMs like Mongoose or Sequelize you need to add the verification fields manually to the user model. These need to be the following fields.isVerified: { type: Boolean },verifyToken: { type: String },verifyExpires: { type: Date },verifyChanges: { type: Object },resetToken: { type: String },resetExpires: { type: Date }
- Finally, we need to add two after create hooks to our user model. One to call our notifier function and one to remove the verification again. That looks like this:
after: { create: [ context => { accountService(context.app).notifier('resendVerifySignup', context.result) }, verifyHooks.removeVerification() ]
Giving us the total result:
Now itâs time for the big test. If you finished all this and set up your mailer correctly, you can send a POST request to the user service to create an account. On doing this, the email should be sent to your email address with a verification link inside. If that works, well done! Now all we need to do is create a client page to handle the click.
Step 5: Verifying the email link
For simplicity we will create a basic html page with a XMLHttpRequest() script to handle the verification. Obviously there are better way to handle this with feathers-client and your favorite frontend library. However, that is out of scope of this article. Following the structure of our verification link we will create a new folder in the /public folder of our app called âverifyâ. Here we will put a new index.html file. All this needs to do is to send a POST request to our /authmanagement service with the following JSONÂ object.
{ âactionâ:âverifySignupLongâ, âvalueâ: YOUR_TOKEN}
So in the end all we need to do is create a script that takes the token parameter from the URL and posts this to our endpoint. For this I have created a sample page which looks like this.
If you have implemented this, the full flow should work. You can test this by clicking on the link you sent yourself earlier and checking that the page shows a successful token sent. This should trigger a second email thanking you for verification.
Step 6: Securing the application
Now that the app works there is only one step to complete and that is adding some security to the users service. Since we have a nice authentication flow running we donât want any users to meddle with the user service directly anymore. For this we create two before hooks. One on the update method and one on the patch method. With the one on the update method we are going to disallow this method in its entirety. After all, we wouldnât want someone to be able to replace our carefully verified user by a new one. The one on the patch method we want to restrict the user from touching any of the authentication field methods directly. To do this we update the user before hooks to:
NOTE: authentication-management has password hashing built in. To prevent double hashing our password we are only hashing it for external calls.Next Steps
There are a lot more things to set up after this and a lot more optimizations to make. You can start by adding fancy email templates instead of the link. Another possibility would be to replace the email transport by something else, for example a short verification token via SMS. Or start adding code for any of the other actions that are covered by feathers-authentication-management. To help you on that please refer to:
The article by Jon Paul Miles https://blog.feathersjs.com/how-to-setup-email-verification-in-feathersjs-72ce9882e744. This covers the rest of the actions and gives more info on how to set up the rest.
The (outdated) documentation https://auk.docs.feathersjs.com/api/authentication/local-management.html.
Thanks for reading and happy coding!
Setting up email verification in FeathersJS was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.