Next.js Discord

Discord Forum

Help with NextAuth

Unanswered
Oriental chestnut gall wasp posted this in #help-forum
Open in Discord
Oriental chestnut gall waspOP
I'm new to NextAuth and auth in general. I'm trying to set up a simple credentials-based sign in page. I am using Prisma as my db.

I have gotten as far as being able to create users with a username/password using a custom route, but I'm lost as far as how to authorize a user.

I am trying to use next-auth/react/signin but I'm pretty sure I'm doing it wrong.

Code examples in the comments

3 Replies

Oriental chestnut gall waspOP
api/auth/[...nextauth]/route.js
import NextAuth from "next-auth";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import CredentialsProvider from "next-auth/providers/credentials";

import prisma from "../../../../../lib/prisma";

export const authOptions = {
  adapter: PrismaAdapter(prisma),
  debug: true,
  pages: { signIn: "/login" },
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        username: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" },
      },
      authorize: authorize(prisma),
    }),
  ],
  session: {
    strategy: "jwt",
  },
};

async function authorize(prisma) {
  return async (credentials) => {
    console.log(credentials);
    console.log("i'm running the authorize function");
    if (!credentials) throw new Error("Missing credentials");
    if (!credentials.username)
      throw new Error('"username" is required in credentials');
    if (!credentials.password)
      throw new Error('"password" is required in credentials');

    const maybeUser = await prisma.user.findFirst({
      where: { username: credentials.username },
      select: { id: true, username: true, password: true },
    });

    if (!maybeUser || !maybeUser.password) return null;

    const isValid = await compare(credentials.password, maybeUser.password);
    if (!isValid) {
      return null;
    }

    return { id: maybeUser.id, username: maybeUser.username };
  };
}

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };
api/user/login
import prisma from "../../../../../lib/prisma";

import { hashPassword } from "../utils";

export default async function handle(req, res) {
  if (req.method === "POST") {
    //login uer
    await loginUserHandler(req, res);
  } else {
    return res.status(405);
  }
}
async function loginUserHandler(req, res) {
  console.log("i'm running the loginUserHandler");

  const { email, password } = req.body;
  if (!email || !password) {
    return res.status(400).json({ message: "invalid inputs" });
  }
  try {
    const user = await prisma.user.findUnique({
      where: { email: email },
      select: {
        id: true,
        name: true,
        email: true,
        password: true,
        image: true,
      },
    });
    if (user && user.password === hashPassword(password)) {
      // exclude password from json response
      return res.status(200).json(exclude(user, ["password"]));
    } else {
      return res.status(401).json({ message: "invalid credentials" });
    }
  } catch (e) {
    throw new Error(e);
  }
}
// Function to exclude user password returned from prisma
function exclude(user, keys) {
  for (let key of keys) {
    delete user[key];
  }
  return user;
}
app/login/page.js (relevant code only)
"use client";

import { useState } from "react";
import { signIn } from "next-auth/react";

import Input from "@/components/Input";
import LabeledElement from "@/components/LabeledElement";
import Button from "@/components/Button";

export default function SignUpPage() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  async function handleSubmit(e) {
    const signInResult = await signIn("credentials", {
      username: username.toLowerCase(),
      password: password,
      redirect: false,
      callbackUrl: "/dashboard",
    });

    console.log(signInResult);
  }
...
}