API with NestJS #40. Confirming the email address

JavaScript NestJS TypeScript

This entry is part 40 of 180 in the API with NestJS

In a lot of web applications, emails play a significant role. If we create an online ordering system, we need to be confident that our users get a confirmation email. When our services include a mailing list, we want to make sure that the provided email is valid. We also might want to implement the password resetting feature, for which the email address is essential. Requiring our users to confirm the email address might also serve as an additional layer of security against bots. Therefore, in this article, we look into confirming the email addresses.

Confirming the email address

First, we need a way to store the information about whether the email is confirmed. To do that, let’s expand on the entity of the user.

user.entity.ts

To confirm the email address, we aim to send an email message with an URL containing the JWT. To do that, we need additional environment variables.

If you want to know more about JWT, check out API with NestJS #3. Authenticating users with bcrypt, Passport, JWT, and cookies

app.module.ts

We’ve already used JWT in other parts of this series. To increase security, we want to use a different secret token to encode and decode JWT for email verification. We also want the token to expire after a few hours in case the email account of our user gets hijacked.

.env

Above, we define the expiration time in seconds.

Sending the verification link

To be able to send the verification link, we need to set up Nodemailer. We’ve already created the that does that in the 25th part of this series. Let’s reuse it in a new service that manages email confirmation.

emailConfirmation.service.ts

verificationTokenPayload.interface.ts

Let’s modify our and use the above service.

authenticationController.ts

Now, as soon as users sign in, they receive a link through email.

Feel free to make the contents of the email more refined.

Confirming the email address

Once the user goes to the link above, our frontend application needs to get the token from the URL and send it to our API. To do support that, we need to create an endpoint for it.

emailConfirmation.controller.ts

confirmEmail.dto.ts

Above, a few notable things are happening. We expect the frontend application to send the token from the URL in the request body back to the API. We then decode it and confirm the email.

emailConfirmation.service.ts

Please notice, that we throw an error if the email is already confirmed. Therefore, our JWT can’t be used more than once.

If the method, we use the to mark the email as confirmed. We need to implement this functionality.

Resending the confirmation link

Since we set an expiration time for our tokens, the user might not use the token on time. Therefore, we should implement a feature of resending the link.

emailConfirmation.controller.ts

A thing worth noting is that we require the user to authenticate before resending the confirmation link. Thanks to that, users can’t require email confirmation for other people.

emailConfirmation.service.ts

A crucial thing to notice security-wise is that sending a new confirmation link doesn’t invalidate the previous links. If we would like to achieve that, we could, for example, store the most recent confirmation token in the database and check it before confirming.

Requiring the email address to be confirmed

Depending on the use case, we might want to prevent the user from accessing certain endpoints if the user didn’t confirm the email. To do that, we can create an additional guard.

emailConfirmation.guard.ts

For our guard to work, we need to attach it to an endpoint.

creditCards.controller.ts

In Typescript, decorators resolve from bottom to top. In our implementation, the requires the object to work properly. Because of that, the crucial thing is to first use the , then apply the .

Summary

In this article, we’ve implemented the feature of confirming email addresses. To do that, we had to send emails containing JWT.  We’ve also created a NestJS guard that we can use to block certain endpoints if the user didn’t confirm the email. With it, we’ve added a feature that might prove to be useful if we depend on email messaging a lot in our application.

Series Navigation<< API with NestJS #39. Reacting to Stripe events with webhooksAPI with NestJS #41. Verifying phone numbers and sending SMS messages with Twilio >>
Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Quantum x7
Quantum x7
3 years ago

There is a library for that !

https://github.com/vh13294/nestjs-url-generator/

Amruth Pillai
Amruth Pillai
1 year ago

I believe keeping the email verification route unguarded and decoding the email from the JWT could be a bit dangerous, as anyone could click the link to confirm the email, even a bot.

For example, there are certain email clients that click on the link to check if it’s spam. This would auto-verify the email address.

Instead, one could guard the verify email flow. The email would contain a link to the frontend with the token, (redirect the user to login if not logged in), then call the verify email API after logging in.

On the controller/service, you would have the email now. Get the user’s stored token from the DB, check it against the token you received and verify them. This way, your token doesn’t necessarily need to be a JWT, instead it could just be a random string of numbers or even an OTP that the user should manually enter.