DEV Community

Cover image for Streamlining Email Verification: A Step-by-Step Guide with Spring Boot and Angular
Anbumani
Anbumani

Posted on

Streamlining Email Verification: A Step-by-Step Guide with Spring Boot and Angular

Hello readers, In this article you will learn a complete email verification process. We will implement this using Java, Spring Boot, and Mongo DB. You find the completed code at the end. Also, the video version is below.

Let us split this process into two parts.

  1. Generating email verification link with the token.
  2. Rest endpoint to verify the token from the link.

Workflow

As the first process, we will generate the token, Store it in DB, and send an email with the confirmation link. This will be included after we persist the user details in the registration.

Additionally you can also create an endpoint that can be utilized when there is an email update.

Generate Token & Send email Workflow

An endpoint that verifies the token by querying the DB and updating the user record that the email has been verified.

Confirm-email endpoint workflow

Code Implementation

Let's create an entity that stores the token. This can be leveraged for future use when there is a business requirement for token expiration and many more.



@Data
@Document
public class EmailConfirmationToken {
    @Id
    private String id;
    @Indexed
    private String token;
    @CreatedDate
    @ReadOnlyProperty
    private LocalDateTime timeStamp;
    @DBRef
    private User user;
}


Enter fullscreen mode Exit fullscreen mode

Below is the repository that will interact with DB.



@Repository
public interface EmailConfirmationTokenRepository extends MongoRepository<EmailConfirmationToken, String> {
    EmailConfirmationToken findByToken(String token);
}


Enter fullscreen mode Exit fullscreen mode

Now repository is ready, Let's create a service that generates the token,

We will make use of "KeyGenerators" from spring security to generate a random 15-byte token.



private static final BytesKeyGenerator DEFAULT_TOKEN_GENERATOR = KeyGenerators.secureRandom(15);
    private static final Charset US_ASCII = Charset.forName("US-ASCII");


Enter fullscreen mode Exit fullscreen mode

Now use the DEFAULT_TOKEN_GENERATOR to generate the token and add it to the entity to store it using the repository we created above.



String tokenValue = new String(Base64.encodeBase64URLSafe(DEFAULT_TOKEN_GENERATOR.generateKey()), US_ASCII);
        EmailConfirmationToken emailConfirmationToken = new EmailConfirmationToken();
        emailConfirmationToken.setToken(tokenValue);
        emailConfirmationToken.setTimeStamp(LocalDateTime.now());
        emailConfirmationToken.setUser(user);
        emailConfirmationTokenRepository.save(emailConfirmationToken);


Enter fullscreen mode Exit fullscreen mode

At this point, the token has been generated and stored in DB. Now let's send out a registration email.

To Configure the email server we are going to use Gmail. Let's move to Gmail-> Manage Accounts -> Security -> click on 2 Step Verification -> Scroll to the end and click on App Passwords -> Enter the application name and get the password.

After you get the password add it to the configuration below,



spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: YOUR_EMAIL
    password: "YOUR APPPLICATION PASSWORD"
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            required: true
            enable: true


Enter fullscreen mode Exit fullscreen mode

Now the email server configuration is ready let's implement the email service as below,

Email service makes use of JavaMailSender API. As we are planning to use HTML messages, I am using the MIME message type and its helper to set the email properties.

We can also isolate the HTML message to a separate file and include it as a stream instead of an inline string.



@Service
public class EmailServiceImpl implements EmailService {

    private final JavaMailSender sender;

    public EmailServiceImpl(JavaMailSender sender) {
        this.sender = sender;
    }

    @Override
    public void sendConfirmationEmail(EmailConfirmationToken emailConfirmationToken) throws MessagingException {
        //MIME - HTML message
        MimeMessage message = sender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setTo(emailConfirmationToken.getUser().getUsername());
        helper.setSubject("Confirm you E-Mail - MFA Application Registration");
        helper.setText("<html>" +
                        "<body>" +
                        "<h2>Dear "+ emailConfirmationToken.getUser().getFirstName() + ",</h2>"
                        + "<br/> We're excited to have you get started. " +
                        "Please click on below link to confirm your account."
                        + "<br/> "  + generateConfirmationLink(emailConfirmationToken.getToken())+"" +
                        "<br/> Regards,<br/>" +
                        "MFA Registration team" +
                        "</body>" +
                        "</html>"
                , true);

        sender.send(message);
    }

    private String generateConfirmationLink(String token){
        return "<a href=http://localhost:8080/confirm-email?token="+token+">Confirm Email</a>";
    }
}


Enter fullscreen mode Exit fullscreen mode

Let's add the token generation and send an email after saving user details in your application.

Let's see how it works in action.

Open the UI and register a User with a valid email address,

Registration

Upon registration, let's look at the DB.

User Document
Email Confirmation Document

Here is the email we received.

Inbox Received confirmation email

Received email body

The first part is completed.

  1. Let's implement the rest endpoint that validates the token,

If there is a security config that limits the authenticated endpoints then add this endpoint to whitelists.



@GetMapping("/confirm-email")
    public ResponseEntity<?> confirmEmail(@RequestParam("token") String token) throws InvalidTokenException {
        try{
            if(userService.verifyUser(token)){
                return ResponseEntity.ok("Your email has been successfully verified.");
            } else {
                return ResponseEntity.ok("User details not found. Please login and regenerate the confirmation link.");
            }
        } catch (InvalidTokenException e){
            return ResponseEntity.ok("Link expired or token already verified.");
        }
    }


Enter fullscreen mode Exit fullscreen mode

Below is the service implementation that will validate the token and update the user record.

Code retries the token from DB with the token received from the endpoint. if there is a token then validate update the user record and delete the token from DB.



@Override
    public boolean verifyUser(String token) throws InvalidTokenException {
        EmailConfirmationToken emailConfirmationToken = emailConfirmationTokenRepository.findByToken(token);
        if(Objects.isNull(emailConfirmationToken) || !token.equals(emailConfirmationToken.getToken())){
            throw new InvalidTokenException("Token is not valid");
        }
        User user = emailConfirmationToken.getUser();
        if (Objects.isNull(user)){
            return false;
        }
        user.setAccountVerified(true);
        userRepository.save(user);
        emailConfirmationTokenRepository.delete(emailConfirmationToken);
        return true;
    }


Enter fullscreen mode Exit fullscreen mode

Let's check the endpoint by clicking on the email link.

Email with confirmation link

Response from server

This endpoint also updated the record and deleted the token,

Updated account verified

Removed the token from DB

We have successfully implemented the registration workflow. Great for reading till the end. Check out the GitHub repository & do comment if have any questions, I am happy to answer all.

Backend code

GitHub logo amaialth / mfaserver

Spring boot backend for MFA

MFA Server

Application for 2FA demo.

APIs Involved

  • login
  • register
  • verifyTotp
  • confrim-email

Dependencies

  • Spring Security
  • Spring Web
  • dev.samstevens.totp



Angular UI

Mfaapplication

Application developed using Angular 14 and Bootstrap.

Components involved.

  • Login
  • Register
  • TOTP
  • Home Module



Top comments (0)