I have this /app/auth/login/route.ts
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'
export async function POST(request: Request) {
const requestUrl = new URL(request.url)
const formData = await request.formData()
const email = String(formData.get('email'))
const password = String(formData.get('password'))
const cookieStore = cookies()
const supabase = createRouteHandlerClient({ cookies: () => cookieStore })
await supabase.auth.signInWithPassword({
email,
password,
})
return NextResponse.redirect(requestUrl.origin, {
status: 301,
})
}
And the page which is on /app/login/page.tsx
import Link from "next/link";
export default function LoginPage() {
return (
<>
<form action="/auth/login" method="post">
<label htmlFor="email">Email</label>
<input name="email" />
<label htmlFor="password">Password</label>
<input type="password" name="password" />
<button>Sign In</button>
</form>
<Link href="/reset-password">Reset Password</Link>
</>
)
}
Those were the codes that I got from the documentation. I am, however, unable to implement where it displays that they have successfully logged in and the error handling.
I followed answers below, however, I am receiving this error:
POST http://localhost:3000/auth/login net::ERR_ABORTED 405 (Method Not> Allowed)
route.ts
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
import { NextApiRequest, NextApiResponse } from 'next'; // Correct import for NextApiRequest and NextApiResponse
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server'; // Correct import for NextResponse
export async function handler(
req: NextApiRequest, // Correct the parameter list
res: NextApiResponse // Correct the parameter list
) {
const jsonBody = await req.body.json(); // Change 'request' to 'req'
const email = jsonBody.email;
const password = jsonBody.password;
const cookieStore = cookies();
const supabase = createRouteHandlerClient({ cookies: () => cookieStore });
try {
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
return res.status(401).json({ message: 'Login failed. Please check your credentials.' });
}
return res.status(200).json({ message: 'Login successful' });
} catch (error) {
console.error('An error occurred:', error);
return res.status(500).json({ message: 'An unexpected error occurred' });
}
}
api/login/page.tsx
'use client'
import { useRouter } from 'next/navigation';
import { useState } from 'react';
export default function LoginPage() {
const router = useRouter();
const [error, setError] = useState<string>('');
const [email, setEmail] = useState<string>('');
const [password, setPassword] = useState<string>('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
try {
const response = await fetch('/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
if (response.status === 200) {
router.push('/');
} else {
if (response.headers.get('content-type')?.includes('application/json')) {
// Check if the response contains JSON data.
const result = await response.json();
setError(result.message);
} else {
// Handle non-JSON responses (e.g., empty responses).
setError('An unexpected error occurred.');
}
}
} catch (error) {
console.log(error, "error on the login page.tsx")
console.error('An error occurred:', error);
setError('An unexpected error occurred.');
}
};
return (
<>
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input
type="email"
name="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Sign In</button>
</form>
{error && <p>{error}</p>}
</>
);
}
2
Answers
I think you should send a POST json request, handling it with javascript:
And in the api:
I see you did implement a route handler for the
/auth/login
endpoint in Next.js, but in your first snippet, you have defined a function namedPOST
. In the second snippet, you have renamed this function tohandler
. It would be clearer to use the same name for this function across both snippets.Since you get a 405, I suppose the server configuration or the route handler not being set up correctly to handle POST requests to this endpoint.
First, make sure the file name of your route handler matches the URL path you are trying to handle. For example, if your route handler is in a file named
route.ts
, make sure it is located atpages/api/auth/login/route.ts
in your project directory.Export your route handler function as the default export from your route handler file.
Also, make sure your route handler is correctly handling POST requests. You can use the
req.method
property to check the HTTP method of the incoming request and respond accordingly.I would assume you are using NextJS 13.4+
Based on those suggestions, the code would be:
Route Handler (
route.ts
):Login Page (
page.tsx
):In the route handler (
route.ts
), I have added a check to make sure the request method is POST usingif (req.method !== 'POST')
.In the login page (
page.tsx
), I fixed the URL in thefetch
function to match the location of the route handler file (/api/auth/login/route
).The all process: