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.
- Generating email verification link with the token.
- 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.
An endpoint that verifies the token by querying the DB and updating the user record that the email has been verified.
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; }
Below is the repository that will interact with DB.
@Repository public interface EmailConfirmationTokenRepository extends MongoRepository<EmailConfirmationToken, String> { EmailConfirmationToken findByToken(String token); }
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");
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);
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
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>"; } }
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,
Upon registration, let's look at the DB.
Here is the email we received.
The first part is completed.
- 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."); } }
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; }
Let's check the endpoint by clicking on the email link.
This endpoint also updated the record and deleted the token,
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
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)