title: How to inform single page application that email was verified?
body: <p>I have vue js application running on localhost:3000 and express js restful api running on localhost:4000.
  Whenever new user registers, the request is sent to /api/v1/signup endpoint and after successfull registration verification email is sent with url including
  localhost:4000/api/v1/verify-email/:token</p>
  <p>After user click link in the email how to inform vue js application that email validated? use socket or ...?</p>
  <p><strong>Register controller</strong></p>
  <pre><code>async store(req, res) {
      let errors = {}
      let valid = false
  
      await signupSchema.validate({
        first_name: req.body.first_name?.trim(),
        last_name: req.body.last_name?.trim(),
        email: req.body.email?.trim(),
        password: req.body.password?.trim(),
        password_confirmation: req.body.password_confirmation?.trim(),
      }, { abortEarly: false })
        .then(() =&gt; valid = true)
        .catch((err) =&gt; {
          err.inner.map((inn) =&gt; errors[inn.path] = inn.errors)
        })
  
      if (!valid) return res.status(400).json({ errors: errors, message: 'Validation errors' }) 
  
      const data = {
        first_name: req.body.first_name.trim(),
        last_name: req.body.last_name?.trim(),
        email: req.body.email.trim(),
        password: bcrypt.hashSync(req.body.password, 12)
      }
  
      let id = null
      
      // create user
      await knex('users').insert(data)
        .then((res) =&gt; id = res[0])
        .catch((err) =&gt; {
          logger.log(err)
          return res.status(500).json({ error: err.message })
        })
  
      // create verification token
      const verificationToken = jwt.sign({ id: id }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: 3600 })
  
      await (new VerificationEmail(verificationToken, { id })).queue(data.email)
  
      const user = await knex('users')
        .select([ 'id', 'email', 'first_name', 'last_name', 'verified_at', 'deleted_at', 'created_at', 'updated_at' ])
        .where('id', id)
        .first()
        .then((res) =&gt; res)
  
      // sign jwt tokens
      const accessToken = jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, { expiresIn: 60 })
      const refreshToken = jwt.sign(user, process.env.REFRESH_TOKEN_SECRET, { expiresIn: '1h' })
  
      return res.json({ id: id, message: 'Successfully registered', accessToken, refreshToken })
    }
  </code></pre>
  <p><strong>VerifyEmailController</strong></p>
  <pre><code>class VerifyEmailController {
    /**
     * 
     * @param {*} req 
     * @param {*} res 
     */
    async store(req, res) {
      const user = await knex('users').where('id', req.params.id).first().then(res)
      if (!user) res.status(404).json({ message: 'User not found' })
      // validate token
      jwt.verify(req.params.token, process.env.ACCESS_TOKEN_SECRET, async (err, data) =&gt; {
        if (err) return res.status(401).json({ message: 'Invalid token' })
        if (data.id !== user.id) res.status(401).json({ message: 'Invalid token' })
        await knex('users').where('id', req.params.id)
          .update({ verified_at: new Date() })
        return res.json({ message: 'Your account verified. Thanks' })
      })
    }
  }
  </code></pre>
  <p><strong>VerificationEmail</strong></p>
  <pre><code>class VerificationEmail {
    token;
    user;
  
    constructor(token, user) {
      this.token = token
      this.user = user
    }
  
    layout(content) {
      const str = fs.readFileSync(path.join(__dirname, '../../views/vendor/mail/default.ejs'), 'utf-8')
      return ejs.render(str, { content })
    }
  
    build() {
      const url = `${process.env.APP_URL}/api/v1/verify-email/${this.user.id}/${this.token}`
      const str = fs.readFileSync(path.join(__dirname, '../../views/email/verification.ejs'), 'utf-8')
      const content = ejs.render(str, { url })
      return this.layout(content)
    }
  
    async queue(to) {
      const html = this.build()
      return emailQueue.add({ to, subject: 'Verify email address', html })
    }
  }
  </code></pre>
  <p><strong>Signup page</strong></p>
  <p><a href="https://i.stack.imgur.com/HTKLq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/HTKLq.png" alt="enter image description here" /></a></p>
  <p><a href="https://i.stack.imgur.com/A0zpv.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/A0zpv.png" alt="enter image description here" /></a></p>