0

I'm trying to set up role based authentication in next.js using next-auth and prisma but when I try to call signIn() function I get a weird error error - TypeError: "ikm"" must be an instance of Uint8Array or a string. The signIn()function invokes the authorize process, when I enter invalid credentials I get unauthorized response. But this error occurs only when the credentials are true.
This is next-auth handler using the credentials provider:

// /api/auth/[...nextauth].ts
export default (req: NextApiRequest, res: NextApiResponse) =>
  NextAuth(req, res, {
    secret: process.env.NEXTAUTH_SECRET,
    adapter: PrismaAdapter(prisma),
    providers: [
      CredentialsProvider({
        id: 'admin-login',
        name: 'Admin login',
        credentials: {
          email: {
            label: 'Email',
            type: 'email',
            placeholder: 'test@test.com',
          },
          password: { label: 'Mot de passe', type: 'password' },
        },
        authorize: async (credentials, request) => {
          const { email, password } = registerSchema.parse(credentials);
          const user = await prisma.user.findFirst({
            where: {
              email,
            },
            select: {
              id: true,
              email: true,
              password: true,
              name: true,
              role: true,
            },
          });
          if (!user) throw new Error('Unauthorized.');
          if (user.role !== 'ADMIN') throw new Error('Unauthorized.');
          const isValid = await verify(user.password, password);
          if (!isValid) throw new Error('Invalid Credentials');
          return {
            id: user.id,
            email: user.email,
            name: user.name,
            role: user.role,
          };
        },
      }),
    ],
    callbacks: {
      async signIn({ user, account, profile, email, credentials }) {
        return true;
      },
      async redirect({ url, baseUrl }) {
        return url.startsWith(baseUrl)
          ? Promise.resolve(url)
          : Promise.resolve(baseUrl);
      },
      async jwt({ token, user, account, profile, isNewUser }) {
        if (user) {
          token.id = user.id;
          token.role = user.role;
        }
        return token;
      },
      async session({ session, token, user }) {
        const sess: Session = {
          ...session,
          user: {
            ...session.user,
            id: token.id as string,
            role: token.role as string,
          },
        };
        return sess;
      },
    },

    session: {
      strategy: 'jwt',
    },
    jwt: {
      secret: process.env.JWT_SECRET,
      maxAge: 30 * 24 * 30 * 60, // 30 days
    },
    pages: {
      signIn: '/auth/login',
      signOut: '/api/auth/logout',
      newUser: '/api/auth/register',
    },
  });

And here is the login page:

// /auth/login.tsx
const LoginPage: NextPage<Props> = ({ csrfToken }) => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<ISignUp & { csrfToken: string }>({ resolver: zodResolver(registerSchema) });
  const onSubmit = async (values: ISignUp & { csrfToken: string }) => {
    try {
      const res = await signIn('admin-login', {
        redirect: false,
        email: values.email,
        password: values.password,
      });
      console.log(res);
    } catch (err) {
      console.error(err);
    }
  };
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...register('csrfToken')}
        type='hidden'
        defaultValue={csrfToken}
        hidden
      />
      <input className='border' {...register('email')} />
      <p>{errors.email?.message}</p>
      <input className='border' {...register('password')} />
      <p>{errors.password?.message}</p>
      <button type='submit'>
        Submit
      </button>
    </form>
  );
};
Ismail_Aj
  • 332
  • 1
  • 4
  • 17

0 Answers0