Thiago Kosudi
Thiago Kosudi

Reputation: 1

Issue verifying token via query param using FastifyJWT: TypeError - request.jwtVerify is not a function

The issue at hand revolves around the utilization of FastifyJWT for token verification in a Fastify application. Specifically, when attempting to perform the verification process on a token received via a query parameter in a GET request, the function request.jwtVerify(token) is producing the error "TypeError: request.jwtVerify is not a function".

The aim is to successfully extract and verify the token received through the URL query parameter in order to confirm a user's email address. The token is generated and sent via an email confirmation link, and upon receiving a GET request with this token, the intention is to validate it using FastifyJWT.

This workflow involves:

    const emailToken = await reply.jwtSign({}, {
      sub: email,
      expiresIn: '7d'
    });

    const messageData = {
      from: '[email protected]',
      to: '[email protected]',
      subject: 'Verificação de E-mail',
      text: `Clique neste link para verificar seu e-mail: ${env.APP_URL}/users/verify/email?token=${emailToken}`,
      html: `<p>Clique neste <a href="${env.APP_URL}/users/verify/email?token=${emailToken}">link</a> para verificar seu e-mail.</p>`
    }

    // Envio do e-mail de verificação
    const resMG = await mgClient.messages.create(env.MAILGUN_DOMAIN, messageData);

    console.log('Email enviado com sucesso: ', resMG)
import { makeVerifyUserEmailUseCase } from "@/application/factories/user/make-verify-user-email-use-case"
import { FastifyReply, FastifyRequest } from "fastify"
import { z } from "zod"

export default async function verifyUserEmail(request: FastifyRequest, reply: FastifyReply) {
  const verifyUserEmailQuerySchema = z.object({
    token: z.string(),
  })

  const { token } = verifyUserEmailQuerySchema.parse(request.query)
  console.log('TOKEN after parse: ', token)

  try {
    const decodedToken = request.jwtVerify({ token } as any, (error, decodedToken) => {
      if (error) {
        console.log('ERROR!')
        console.error(error)
        return reply.status(401).send('Erro na verificação do token')
      }
      return decodedToken
    })

    console.log('DECODED TOKEN: ', decodedToken)

    const emailToken = (decodedToken as any).sub.email
    console.log(emailToken)
    if ((decodedToken as any) && (decodedToken as any).sub?.email) {
      const verifyUserEmailUseCase = makeVerifyUserEmailUseCase()
      await verifyUserEmailUseCase.execute(emailToken)

      return reply.status(200).send({ message: 'E-mail verificado com sucesso!' })
    }
  } catch (error) {
    console.error(error)
  }

}

However, the code is encountering an issue with the request.jwtVerify() function, which seems to be unavailable or improperly utilized, resulting in the mentioned error.

The goal is to gain insights into why this error is occurring and how to rectify it, enabling successful token verification using FastifyJWT.

In attempting to resolve the issue, I first ensured that the @fastify/jwt plugin was correctly installed and configured within the application. The plugin setup appears to be in place:

import fastifyJwt from '@fastify/jwt'

app.register(fastifyJwt, {
  secret: env.JWT_SECRET,
  cookie: {
    cookieName: 'refreshToken',
    signed: false,
  },
  sign: {
    expiresIn: '10m',
  },
})

Any doubts are welcome, in case you need further information, I'm open to providing it. Thank you in advance for any assistance.

Upvotes: 0

Views: 300

Answers (2)

Nick
Nick

Reputation: 5198

I ran into the same issue. Have one-time use tokens I want to use via query parameters. fastify-jwt only seems to support cookie and Authorization header methods to obtain the JWT. So, token isn't an option for request.jwtVerify(), it's looking for the token elsewhere. See the requestVerify function in the source repo.

So, I ended up rolling my own middleware to grab it from the query parameters, using the very similar jwt library:

import jwt from 'jsonwebtoken';

export async function oneTimeUseToken(request: FastifyRequest) {
  try { 
    const { jwtString } = request.query as any;

    const payload: any = jwt.verify(jwtString, secretKey);

    request.oneTimeUseToken = payload;
  } catch (err) {
    // ...
  }
}

It could probably be improved to use the same jwt library fastify-jwt brings in.

Upvotes: 0

Howard Medeiros
Howard Medeiros

Reputation: 1

Try:

import { makeVerifyUserEmailUseCase } from "@/application/factories/user/make-verify-user-email-use-case";
import { FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";

export default async function verifyUserEmail(request: FastifyRequest, reply: FastifyReply) {
  const verifyUserEmailQuerySchema = z.object({
    token: z.string(),
  });

  try {
    const { token } = verifyUserEmailQuerySchema.parse(request.query) as { token: string };
    console.log('TOKEN after parse: ', token);

    const decodedToken = await request.jwtVerify({ token });

    console.log('DECODED TOKEN: ', decodedToken);

    const emailToken = decodedToken.sub.email;
    console.log(emailToken);

    if (decodedToken && decodedToken.sub?.email) {
      const verifyUserEmailUseCase = makeVerifyUserEmailUseCase();
      await verifyUserEmailUseCase.execute(emailToken);

      return reply.status(200).send({ message: 'E-mail verificado com sucesso!' });
    }
  } catch (error) {
    console.error(error);
    return reply.status(401).send('Erro na verificação do token');
  }
}

Upvotes: 0

Related Questions