Adonis Persona VerifyEmail 400 error "The token is invalid or expired"

I’m using Adonis Persona for user authentication and having issues with encoding the token for the email link.

Using Persona.register() in the UserController

async register({ request, auth, response }) {
    const payload = request.only([
      "email",
      "first_name",
      "last_name",
      "password",
      "password_confirmation"
    ]);
    const { first_name, last_name } = request.all();
    payload.full_name = `${first_name} ${last_name}`;
    payload.profile_image_source = `https://ui-avatars.com/api/?name=${first_name}+${last_name}`;
    const user = await Persona.register(payload);
    return await auth.generate(user);
  }

I’m then sending a mail to the user, in start/events.js:

const querystring = require("querystring");
const Env = use("Env");
const Event = use("Event");
const Mail = use("Mail");

Event.on("user::created", async payload => {
  const { user, token } = payload;

  await Mail.send("new.user", { user: user.toJSON(), token: querystring.encode(token) }, message => {
    message
      .to(payload.user.email)
      .from(`<${Env.get("MAIL_USERNAME")}>`)
      .subject("Thanks for registering!");
  });
});

In resources/new/user.edge

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Welcome</title>
</head>
<body>
  <section>
      <p>Website Analyzer App Registration Confirmation</p>
      <p>
        Welcome, {{ user.full_name }}. Thanks for registering.
      </p>
    <a href="http://localhost:3000/users/verify-email?token={{token}}">Verify your email</a>
  </section>
</body>
</html>

The email link shows the token query parameter as something like http://localhost:3000/users/verify-email?token=

So, querystring.encode(token) is returning an empty string?

If I don’t use the encode method and pass the token string as is, I’m getting the 400 error with the message “The token is invalid or expired” which is true since the token query param doesn’t match the token string in the database.

token from url: 97d40ac0ce62e9f2657bd84befb405bdcj1u6jL%2FqQTAGIOeGLOCbgGUe548gl0RfiLx%20Tn3UCs%3D

token from db97d40ac0ce62e9f2657bd84befb405bdcj1u6jL/qQTAGIOeGLOCbgGUe548gl0RfiLx+Tn3UCs=

I’m sure I just don’t know how to properly use url encoding but I’ve Googled my heart out and am at a loss on how to properly pass the token to the email’s url link.

EDIT

So I ‘solved’ this by using encodeURIComponent() on the token in event.js when passing it to the edge view. Still not sure how to do this with querystring.encode().

In start/events.js:

const querystring = require("querystring");
const Env = use("Env");
const Event = use("Event");
const Mail = use("Mail");

Event.on("user::created", async payload => {
  const { user, token } = payload;

  await Mail.send(
    "new.user",
    { user: user.toJSON(), token: encodeURIComponent(token) },
    message => {
      message
        .to(payload.user.email)
        .from(`<${Env.get("MAIL_USERNAME")}>`)
        .subject("Thanks for registering!");
    }
  );
});

2 Likes

Glad you figured that one out :slight_smile:

Can you try this to implement with querystring?

const token = querystring.encode({
    token: data.token,
  });

… and provide token in email.

2 Likes

Your snippet works!

I guess I needed to pass the token as an object instead of a string to querystring.encode().

2 Likes