diff --git a/src/app/api/auth/actions.ts b/src/app/api/auth/actions.ts index ea6a472..5a3f1d3 100644 --- a/src/app/api/auth/actions.ts +++ b/src/app/api/auth/actions.ts @@ -1,13 +1,16 @@ "use server" import prisma from 'app/lib/db'; -import { jwtVerify, JWTPayload, decodeJwt } from 'jose'; +import { jwtVerify, JWTPayload, decodeJwt, SignJWT } from 'jose'; import { cookies } from 'next/headers'; - +import { loginSchema, LoginSchema } from 'app/login/schema'; +import { NextResponse } from 'next/server'; +import { TextEncoder } from 'util'; export async function getJWTSecretKey() { const secret = process.env.JWT_SECRET if (!secret) throw new Error("There is no JWT secret key") - return new TextEncoder().encode(secret) + const enc: Uint8Array = new TextEncoder().encode(secret) + return enc } export async function verifyJwt(token: string): Promise { @@ -76,25 +79,20 @@ export async function setUserDataCookie(userData) { }) } -export type UserLogin = { - email: string, - password: string -} -export async function login(userLogin: UserLogin) { +export async function login(userLogin: LoginSchema) { + const isSafe = loginSchema.safeParse(userLogin) try { + + if (!isSafe.success) throw new Error("parse failed") const user = await prisma.user.findFirst({ where: { email: userLogin.email } }) - if (!user) { throw new Error('user does not exist') } + if (!user) throw new Error("user does not exist") const bcrypt = require("bcrypt"); - console.log(`client user: ${JSON.stringify(userLogin)} - db user: ${JSON.stringify(user)}`) const passwordIsValid = await bcrypt.compare(userLogin.password, user.password) - if (!passwordIsValid) throw new Error('invalid password') - //return the user object without the hashed password - return { email: user.email, id: user.id } + if (!passwordIsValid) throw new Error("password is not valid") + return { email: userLogin.email } } catch (error) { - console.error(error) - throw new Error('invalid login or password') + throw new Error('login failed') } } diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts index 329e8bd..aa46161 100644 --- a/src/app/api/auth/login/route.ts +++ b/src/app/api/auth/login/route.ts @@ -1,4 +1,5 @@ import { NextResponse, NextRequest } from "next/server"; +import prisma from "app/lib/db"; import { SignJWT } from "jose"; import { getJWTSecretKey, login, setUserDataCookie } from "../actions"; @@ -13,9 +14,9 @@ const dynamic = 'force-dynamic' //POST endpoint export async function POST(request: NextRequest) { - const { body } = await request.json() - const { email, password } = body + const body = await request.json() console.log(`body: ${JSON.stringify(body)}`) + const { email, password } = body if (!email || !password) { const res = { @@ -37,7 +38,7 @@ export async function POST(request: NextRequest) { .setProtectedHeader({ alg: 'HS256' }) .setIssuedAt() .setExpirationTime('1h') - .sign(getJWTSecretKey()) + .sign(await getJWTSecretKey()) //make response const res = { success: true } diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 2ecd228..80c4a70 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -6,28 +6,44 @@ import { toast } from "@/components/ui/use-toast"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; -import { login } from "app/api/auth/actions"; +import { redirect } from "next/navigation"; +import { loginSchema } from "./schema"; +import { useRouter } from "next/navigation"; -const formSchema = z.object({ - email: z.string().email(), - password: z.string().min(6) -}) export default function LoginForm() { - const form = useForm>({ - resolver: zodResolver(formSchema), + const router = useRouter() + const form = useForm>({ + resolver: zodResolver(loginSchema), }) - function onErrors(errors) { - toast({ - title: "WHOOPS", - description: JSON.stringify(errors) + const onSubmit = form.handleSubmit(async (data) => { + // const res = await login(data) + // if (res?.error) { + // toast({ title: "Whoops!", description: res.error }) + // form.reset() + // } else { + // toast({ title: "login successful" }) + // } + const res = await fetch('/api/auth/login', { + method: 'POST', + headers: { + 'Content-type': 'application/json', + }, + body: JSON.stringify(data), }) - } + if (res.status === 200) { + toast({ title: "login successful!" }) + router.push('/submission') + } else { + toast({ title: "login failed!" }) + } + }) + return (
- + diff --git a/src/middleware.ts b/src/middleware.ts index 44a89ca..4703e6b 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -17,10 +17,9 @@ export default async function(request: NextRequest) { // const url = `${process.env.NEXT_PUBLIC_BASE_URL}/login?redirect=${request.nextUrl.pathname + request.nextUrl.search}` const url = request.nextUrl.clone() url.pathname = "/login" - if (protectedRoutes.some(pattern => matchesWildcard(request.nextUrl.pathname, pattern))) { const token = request.cookies.get('token') - + console.log(`token: ${JSON.stringify(token)}`) //NOTE - may need to add logic to return 401 for api routes if (!token) { @@ -30,9 +29,9 @@ export default async function(request: NextRequest) { try { //decode and verify jwt cookie const jwtIsVerified = await verifyJwt(token.value) - if (!jwtIsVerified) { //delete token + console.log('could not verify jwt') request.cookies.delete('token') return NextResponse.redirect(url) }