Next-Auth EmailProvider invalidating token before it is used

  Kiến thức lập trình

Really confused about this. I am setting up a magic link email with next-auth email provider and postmark. The token is created successfully in the db and the email sends fine, but when clicking the magic link I am getting a:

Unable to sign in
The sign in link is no longer valid.
It may have been used already or it may have expired.

at http://localhost:3000/api/auth/error?error=Verification

It seems to me it could be a race condition or something, but I have logged out all the functions from within the mongo adapter and it seems to all be fine.

Here is my next-auth setup:

import NextAuth, { NextAuthOptions, Session } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import EmailProvider from "next-auth/providers/email";
import user from "../../../../models/user.model";
import { connectDatabase } from "../../../../utils/db";
import { User } from "../../../../types/models";
import { UserSession, UserToken } from "../../../../types/auth";
import { JWT } from "next-auth/jwt";
import { Client } from "postmark";
import { MongoClient } from "mongodb";
import { MongoDBAdapter } from "@next-auth/mongodb-adapter";

const postmarkClient = new Client(process.env.POSTMARK_API_TOKEN!);
const mongoClient = new MongoClient(process.env.NEXTAUTH_MONGODB!);
const mongoClientPromise = mongoClient.connect();

export const nextAuthOptions: NextAuthOptions = {
  adapter: MongoDBAdapter(mongoClientPromise),
  providers: [
    EmailProvider({
      server: {
        host: process.env.SMTP_HOST,
        port: Number(process.env.SMTP_PORT),
        auth: {
          user: process.env.SMTP_USER,
          pass: process.env.SMTP_PASSWORD,
        },
      },
      from: process.env.SMTP_FROM,
      sendVerificationRequest: async ({ identifier, url, provider }) => {
        const result = await postmarkClient.sendEmailWithTemplate({
          TemplateId: 35449071,
          To: identifier,
          From: provider.from,
          TemplateModel: {
            name: "Sam",
            magic_link: url,
          },
        });

        if (result.ErrorCode) {
          throw new Error(result.Message);
        }
      },
    }),
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
  ],
  callbacks: {
    async jwt({ token }: { token: JWT }) {
      await connectDatabase();
      if (!(token as UserToken).user?._id) {
        await user.findOne({ email: token.email }).then((user) => {
          if (user)
            token.user = {
              ...(token as UserToken).user,
              ...user.toJSON(),
            } as User;
        });
      }
      return token;
    },
    async session({ session, token }: { session: Session; token: JWT }) {
      delete token.password;
      return { ...session, ...token };
    },
  },
  events: {},
};

const handler = NextAuth(nextAuthOptions);

export { handler as GET, handler as POST };

LEAVE A COMMENT