Next-Auth: Credentials Provider failing unexpectetly with custom login page.
Answered
Egyptian Mau posted this in #help-forum
Egyptian MauOP
Next 14, App Router
I am new to next auth and next.js itself, I am trying to implement a credentials provider that sends creds to a node server and gets a JWT token in return.
My implementation works when using the standard login page next auth generates, but when I try to make a custom one nothing happens when I click log in and I get the error you can see on the screenshot.
I am new to next auth and next.js itself, I am trying to implement a credentials provider that sends creds to a node server and gets a JWT token in return.
My implementation works when using the standard login page next auth generates, but when I try to make a custom one nothing happens when I click log in and I get the error you can see on the screenshot.
Answered by Ray
'use server';
import { signIn } from "../auth";
export async function authenticate(
prveState: string | undefined,
formData: FormData
) {
try {
const email = formData.get("email");
const password = formData.get("password");
await signIn("credentials", { email, password });
} catch (error) {
if (error) {
switch (error.type) {
case "CredentialsSignin":
return "Invalid credentials";
default:
return "Something went wrong";
}
}
}
}I think you are missing
'use server' in action.ts9 Replies
Egyptian MauOP
/login page:
"use client";
import React from "react";
import { useFormState, useFormStatus } from "react-dom";
import { authenticate } from "@/actions";
const LoginForm = () => {
const [errorMessage, dispatch] = useFormState(authenticate, undefined);
return (
<>
<div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
<form className="space-y-6" action={dispatch}>
<div>
<label
htmlFor="email"
className="block text-sm font-medium leading-6 text-gray-900"
>
Email address
</label>
<div className="mt-2">
<input
id="email"
name="email"
type="email"
autoComplete="email"
required
/>
</div>
</div>
<div>
<div>
<label
htmlFor="password"
>
Password
</label>
<div className="text-sm">
<a
href="#"
className="font-semibold text-indigo-600 hover:text-indigo-500"
>
Forgot password?
</a>
</div>
</div>
<div className="mt-2">
<input
id="password"
name="password"
type="password"
autoComplete="current-password"
required/>
</div>
</div>
<div>
<LoginButton />
</div>
</form>
</div>
</div>
</>
);
};
export default LoginForm;
function LoginButton() {
const { pending } = useFormStatus();
return (
<button
aria-disabled={pending}
type="submit"
>
Sign in
</button>
);
}auth.ts:
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import CredentialsProvider from "next-auth/providers/credentials";
import type { NextAuthConfig } from "next-auth";
export const config = {
theme: {
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
},
pages: {
signIn: "/login",
},
providers: [
GitHub,
CredentialsProvider({
name: "Credentials",
credentials: {
email: {
label: "Email",
type: "email",
placeholder: "email@example.com",
},
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
const { email, password } = credentials as any;
const res = await fetch("http://localhost:5000/api/user/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
});
const data = await res.json();
if (res.ok && data) {
return data.user;
}
return null;
},
}),
],
callbacks: {
authorized({ request, auth }) {
const { pathname } = request.nextUrl;
if (pathname === "/login") return !!auth;
return true;
},
},
} satisfies NextAuthConfig;
export const { handlers, auth, signIn, signOut } = NextAuth(config); actions.ts:
import { signIn } from "../auth";
export async function authenticate(
prveState: string | undefined,
formData: FormData
) {
try {
const email = formData.get("email");
const password = formData.get("password");
await signIn("credentials", { email, password });
} catch (error) {
if (error) {
switch (error.type) {
case "CredentialsSignin":
return "Invalid credentials";
default:
return "Something went wrong";
}
}
}
}@Egyptian Mau Next 14, App Router
I am new to next auth and next.js itself, I am trying to implement a credentials provider that sends creds to a node server and gets a JWT token in return.
My implementation works when using the standard login page next auth generates, but when I try to make a custom one nothing happens when I click log in and I get the error you can see on the screenshot.
'use server';
import { signIn } from "../auth";
export async function authenticate(
prveState: string | undefined,
formData: FormData
) {
try {
const email = formData.get("email");
const password = formData.get("password");
await signIn("credentials", { email, password });
} catch (error) {
if (error) {
switch (error.type) {
case "CredentialsSignin":
return "Invalid credentials";
default:
return "Something went wrong";
}
}
}
}I think you are missing
'use server' in action.tsAnswer
Egyptian MauOP
That is it, thanks a lot! Can you explain to me, I thought next.js defaults to use server, why do I need to specify it?
because the server action invoke on the client
Egyptian MauOP
Thats fair, thanks a bunch.
https://react.dev/reference/react/use-server
you can read more in here
you can read more in here