Skip to main content

Kotlin + Spring + Vue: Email Registration Confirmation

To avoid a flood of fake users let's implement the email registration confirmation.

The Algorithm

  1. Create the new account setting isEnabled field value to false.
  2. Generate a random string token which will be a key for registration confirmation.
  3. Send this token to a newly registered user providing a convenient link already containing it.
  4. Set isEnabled account field to true, after user followed the link sent in specified period of time.

Backend

Database

At first, we need a new table for registration tokens storing:

CREATE TABLE public.verification_token
(
     id serial NOT NULL,
     token character varying,
     expiry_date timestamp without time zone,
     user_id integer,
     PRIMARY KEY (id)
);

ALTER TABLE public.verification_token
ADD CONSTRAINT verification_token_users_fk FOREIGN KEY (user_id)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE;


And, of course, new entity class:
And repository:

Services

Then we need to implement features for token management - create, validate and send by email.
Update UserDetailsServiceImpl adding methods for token creation and validation:

override fun createVerificationTokenForUser(token: String, user: User) {
     tokenRepository.save(VerificationToken(token, user))
}

override fun validateVerificationToken(token: String): String {
     val verificationToken: Optional<VerificationToken> = tokenRepository.findByToken(token)

     if (verificationToken.isPresent) {
          val user: User = verificationToken.get().user
          val cal: Calendar = Calendar.getInstance()
          if ((verificationToken.get().expiryDate.time - cal.time.time) <= 0) {
               tokenRepository.delete(verificationToken.get())
               return TOKEN_EXPIRED
          }

          user.enabled = true
          tokenRepository.delete(verificationToken.get())
          userRepository.save(user)
          return TOKEN_VALID
     } else {
          return TOKEN_INVALID
     }
}



Now it's time to create a method for confirmation email sending - update our EmailServiceImpl:

    @Value("\${host.url}")
    lateinit var hostUrl: String

    @Autowired
    lateinit var userDetailsService: UserDetailsServiceImpl

...

    override fun sendRegistrationConfirmationEmail(user: User) {
        val token = UUID.randomUUID().toString()
        userDetailsService.createVerificationTokenForUser(token, user)
        val link = "$hostUrl/?token=$token&confirmRegistration=true"
        val msg = "<p>Please, follow the link to complete your registration:</p><p><a href=\"$link\">$link</a></p>"
        user.email?.let{sendHtmlMessage(user.email!!, "KSVG APP: Registration Confirmation", msg)}
    }



NOTE:
  • I recommend take host URL as application.properties parameter
  • In our link we send two GET parameters (token and confirmRegistration) to the default page. I will explain why a bit later


Controllers

Modify our AuthController:
  1. Set isEnabled field value to false for the new users
  2. Send confirmation email after creating a new account
  3. Create controller for token validation
  4. IMPORTANT: check whether account is confirmed while user is logging in
That's all for this part. Let's look at our frontend.

Frontend

At first, we need to create a new component for registration confirm, so

#1 Create a new component RegistrationConfirmPage.vue
#2 Add a new route to router.js with parameter :token:

{
        path: '/registration-confirm/:token',
        name: 'RegistrationConfirmPage',
        component: RegistrationConfirmPage
}

#3 Update SignUp.vue - say new users that they have to follow the link in the email.
#4 IMPORTANT: Unfortunately, we have no ability to provide a fixed link to some specific component which could validate the token. All the links from external sources (e.g. email) will forward us to the default application page. But we are able to tell our application that we want to confirm our registration and provide a token by using GET-parameters. So we need to create a special handler in the App.vue which redirects us to RegistrationConfirmPage.vue with :token parameter after home page is loaded:

methods: {
    confirmRegistration() {
      if (this.$route.query.confirmRegistration === 'true' && this.$route.query.token != null) {
        this.$router.push({name: 'RegistrationConfirmPage', params: { token: this.$route.query.token}});
      }
    },

...

mounted() {
    this.confirmRegistration();
  }



#5 And finally we can finish the creating of RegistrationConfirmPage.vue which sends the token to backend controller and show the message depending on request success:

Ways to Improve

  • Use events and listeners
  • Create a beautiful confirmation email

Links

Comments

Popular posts from this blog

Make Authentication More Secure With Cookies Email Registration Confirmation That's all for this year. See you in 2020!

Kotlin + Spring Boot + Vue.js: + Gradle

Hello, dear visitors! I added two new articles to the Fullstack section: Kotlin + Spring + Vue: Migration from Maven to Gradle Kotlin + Spring + Vue: Deploy to Heroku with Gradle I'll be glad if you will find then useful for yourself.

Kotlin + Spring Boot + Vue.js

Hello there! I've published my first set of articles about developing web applications using Kotlin , Spring Boot and Vue.js : Koltin + Spring Boot + Vue.js Here are the contents of this set: Introduction Start CI/CD REST API Database Connection Authentication Spam Protection (reCAPTCHA) Email