skip to Main Content

I was trying to learn nextAuth using some tutorial videos on youtube. And I stumbled on a problem.
This is my app/api/auth/[...nextauth].js file

import NextAuth from "next-auth";
export default NextAuth({
  providers: [
    CredentialsProvider({
      name: "Credentials",

      credentials: {
        username: { label: "Username", type: "text", placeholder: "jsmith" },
        password: { label: "Password", type: "password" },
      },

      async authorize(credentials, req) {
        const res = await fetch("/login", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            username: credentials?.username,
            password: credentials?.password,
          }),
        });

        const user = await res.json();
        if (user) {
          return user;
        } else {
          return null;
        }
      },
    }),
  ],
  pages: {
    signIn: "/login",
  },
});

My login page is (whose path is app/login.js is

"use client";
import style from "./login.module.css";
import username from "./username-icon.png";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faUser } from "@fortawesome/free-solid-svg-icons";
import { faLock } from "@fortawesome/free-solid-svg-icons";
import { useReducer } from "react";
import { signIn } from "next-auth/react";
function Login() {
  const [state, dispatch] = useReducer(reducer, {
    username: null,
    password: null,
  });

  function reducer(state, action) {
    switch (action.type) {
      case "name": {
        return {
          username: action.name,
          password: state.password,
        };
      }

      case "pass": {
        return {
          username: state.username,
          password: action.password,
        };
      }
    }
  }

  async function submitHandler(event) {
      const result = await signIn("credentials", {
      username: state.username,
      password: state.password,
      redirect: true,
      callbackUrl: "/admin",
    });
  }

  return (
    <div className={style.main}>
      <div className={style.mainform}>
        <div className={style.login}>Login</div>

        <div>
          <form onSubmit={submitHandler}>
            <div className={style.nameborder}>
              <FontAwesomeIcon
                icon={faUser}
                 style={{
                  color: "rgba(85,86,88,0.8)",
                  marginRight: "15px",
                  fontSize: "20px",
                }}
              />
              <input
                className={style.name}
                name="name"
                placeholder="Username"
                type="text"
                onChange={(e) => {
                  dispatch({
                    type: "name",
                    name: e.target.value,
                  });
                }}
              ></input>
            </div>
            <div className={style.passborder}>
             <FontAwesomeIcon
                icon={faLock}
                style={{
                  color: "rgba(85,86,88,0.8)",
                   marginRight: "15px",
                  fontSize: "20px",
                }}
              />
              <input
                className={style.password}
                name="password"
                placeholder="Password"
                type="password"
                onChange={(e) => {
                  dispatch({
                    type: "pass",
                    password: e.target.value,
                  });
                }}
              ></input>
            </div>
            <input
              type="submit"
              name="login"
              value="Login"
              className={style.loginbutton}
            ></input>
          </form>
        </div>
      </div>
    </div>
  );
}
export default Login;

This is my root page whose path ia app/page.js where I tried to excess session

"use client";
import { signIn, signOut, useSession } from "next-auth/react";
export default function Home() {
  const { data: session } = useSession();
  console.log(useSession());

  return (
    <div>
      {session?.user ? (
        <button onClick={() => signOut()}>signout</button>
      ) : (
        <button onClick={() => signIn()}>signin</button>
      )}
    </div>
  );
}

I have also wrapped Provide.js with SessionProvider and layout.js with Provider

When I open the site on the app on the browser it shows following error

:3000/api/auth/session:1  Failed to load resource: the server responded with a status 
of 404 (Not Found)

[next-auth][error][CLIENT_FETCH_ERROR] https://next- 
auth.js.org/errors#client_fetch_error Unexpected token '<', "<!DOCTYPE 
"... is not valid JSON

Failed to load resource: the server responded with a status of 404 (Not Found)

I don’t know whether the tutorial went wrong or I. I have been stuck in this problem from 2 days. Please help

2

Answers


  1. In Nextjs 13 APP Directory, api are exposed through route.ts file. Firstly, your auth route is not correctly configured. It should look like this :

    api/auth/[...nextauth]/route.ts

    In your route.ts file

    import NextAuth from "next-auth";
    export default NextAuth({
      providers: [
        CredentialsProvider({
          name: "Credentials",
    
          credentials: {
            username: { label: "Username", type: "text", placeholder: "jsmith" },
            password: { label: "Password", type: "password" },
          },
    
          async authorize(credentials, req) {
            const res = await fetch("/login", {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                username: credentials?.username,
                password: credentials?.password,
              }),
            });
    
            const user = await res.json();
            if (user) {
              return user;
            } else {
              return null;
            }
          },
        }),
      ],
      pages: {
        signIn: "/login",
      },
    });
    

    Let me know if this helps 😀

    Login or Signup to reply.
  2. The correct location of the NextAuth configuration file under the app router is app/api/auth/[...nextauth]/route.js and it is expected to export GET and POST named exports.

    import NextAuth from "next-auth";
    import CredentialsProvider from "next-auth/providers/credentials";
    
    const handler = NextAuth({
      providers: [
        CredentialsProvider({
          name: "Credentials",
          credentials: {
            username: { label: "Username", type: "text", placeholder: "jsmith" },
            password: { label: "Password", type: "password" },
          },
          async authorize(credentials) {
            // TODO: implement authentication
            if (credentials?.username === "jsmith") {
              return {
                name: "J Smith",
                email: "[email protected]",
              };
            }
    
            return null;
          },
        }),
      ],
      pages: {
        signIn: "/login",
      },
    });
    
    export { handler as GET, handler as POST };
    

    See configuration documentation here – https://next-auth.js.org/configuration/initialization#route-handlers-app

    Also, you do not have to use the reducer to maintain the login form state. It can simplified as follows.

    "use client";
    
    import * as React from "react";
    import { useRouter } from "next/navigation";
    import { signIn } from "next-auth/react";
    
    export default function Login() {
      const router = useRouter();
    
      const onSubmit = async (event) => {
        event.preventDefault();
    
        const form = new FormData(event.target);
    
        const username = form.get("username");
        const password = form.get("password");
    
        const result = await signIn("credentials", {
          username,
          password,
          redirect: false,
        });
    
        if (!result.error) {
          router.push("/");
        }
    
        // TODO: handle error
      };
    
      return (
        <form onSubmit={onSubmit}>
          <input required name="username" type="text" placeholder="jsmith" />
          <input required name="password" type="password" />
    
          <input type="submit" value="login" />
        </form>
      );
    }
    

    Here is a working example with source code.

    P.S. Also, do not forget to specify NEXTAUTH_URL and NEXTAUTH_SECRET environment variables in the .env file.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search