Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 34 additions & 13 deletions app/(pages)/(hackers)/_components/AuthForms/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useRouter } from 'next/navigation';

import LoginAction from '@actions/auth/login';
import AuthForm from '@components/AuthForm/AuthForm';
import { signIn } from 'next-auth/react';

export default function LoginForm() {
const router = useRouter();
Expand Down Expand Up @@ -33,19 +34,39 @@ export default function LoginForm() {
},
];

const handleGoogleLogin = async () => {
await signIn('google', { callbackUrl: '/' });
};

return (
<AuthForm
role="hacker"
fields={formFields}
buttonText="Log in →"
linkText="Forgot Password?"
linkHref="/login/forgot-password"
initialValues={{
email: '',
password: '',
}}
onSubmit={onSubmit}
onSuccess={onSuccess}
/>
<div>
<AuthForm
role="hacker"
fields={formFields}
buttonText="Log in →"
linkText="Forgot Password?"
linkHref="/login/forgot-password"
initialValues={{
email: '',
password: '',
}}
onSubmit={onSubmit}
onSuccess={onSuccess}
/>
<button
onClick={handleGoogleLogin}
style={{
marginTop: '1rem',
padding: '0.75rem 1.5rem',
backgroundColor: '#4285F4',
color: '#fff',
borderRadius: '6px',
fontWeight: 'bold',
cursor: 'pointer',
}}
>
Sign in with Google
</button>
</div>
);
}
96 changes: 75 additions & 21 deletions auth.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import NextAuth, { DefaultSession } from 'next-auth';
import 'next-auth/jwt';
import Credentials from 'next-auth/providers/credentials';
import { compare } from 'bcryptjs';
import { z } from 'zod';
import NextAuth, { DefaultSession } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import "next-auth/jwt";
import Credentials from "next-auth/providers/credentials";
import { compare } from "bcryptjs";
import { z } from "zod";

import { GetManyUsers } from '@datalib/users/getUser';
import { GetManyUsers } from "@datalib/users/getUser";

declare module 'next-auth' {
declare module "next-auth" {
interface User {
id?: string;
email?: string | null;
Expand All @@ -18,32 +19,32 @@ declare module 'next-auth' {
id: string;
email: string;
role: string;
} & DefaultSession['user'];
} & DefaultSession["user"];
}
}

declare module 'next-auth/jwt' {
declare module "next-auth/jwt" {
interface JWT {
id: string;
email: string;
role: string;
}
}

const emailSchema = z.string().email('Invalid email address.');
const emailSchema = z.string().email("Invalid email address.");

const passwordSchema = z
.string()
.min(6, { message: 'Password must be at least 6 characters long.' })
.max(20, { message: 'Password cannot be longer than 20 characters.' });
.min(6, { message: "Password must be at least 6 characters long." })
.max(20, { message: "Password cannot be longer than 20 characters." });

export const { auth, handlers, signIn, signOut } = NextAuth({
session: { strategy: 'jwt' },
session: { strategy: "jwt" },
providers: [
Credentials({
credentials: {
email: { label: 'email', type: 'text' },
password: { label: 'password', type: 'password' },
email: { label: "email", type: "text" },
password: { label: "password", type: "password" },
},
async authorize(credentials) {
try {
Expand All @@ -55,14 +56,14 @@ export const { auth, handlers, signIn, signOut } = NextAuth({
const response = await GetManyUsers({ email });

if (!response.ok || response.body.length === 0) {
throw new Error(response.error ?? 'User not found.');
throw new Error(response.error ?? "User not found.");
}

const user = response.body[0];

const passwordCorrect = await compare(password, user.password);
if (!passwordCorrect) {
throw new Error('Invalid email address or password.');
throw new Error("Invalid email address or password.");
}

return {
Expand All @@ -72,29 +73,82 @@ export const { auth, handlers, signIn, signOut } = NextAuth({
};
} catch (error) {
if (error instanceof z.ZodError) {
const errorMessage = error.errors.map((e) => e.message).join(' ');
const errorMessage = error.errors.map((e) => e.message).join(" ");
throw new Error(errorMessage);
}
throw error;
}
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
scope: "openid email profile",
},
},
}),
],
callbacks: {
async jwt({ token, user }) {
// When user first logs in (Google or Credentials)
if (user) {
token.id = user.id ?? 'User ID not found';
token.email = user.email ?? 'User email not found';
token.role = user.role;
console.log("Jwt() got user:", user);
// Try to get user data from your MongoDB
const dbUser = await GetManyUsers({ email: user.email });
if (dbUser.ok && dbUser.body.length > 0) {
token.role = dbUser.body[0].role;
token.id = dbUser.body[0]._id.toString();
} else {
token.role = "unknown";
}
}

console.log("Final JWT token:", token);
return token;
},
async session({ session, token }) {
console.log("Session() token:", token);
session.user.id = token.id;
session.user.email = token.email;
session.user.role = token.role;
console.log("Final session object:", session);
return session;
},
async signIn({ account, profile }) {
console.log("Account info:", account);
console.log("Profile info:", profile);

if (!account || !profile?.email) {
console.log("[NextAuth] Missing account or profile", {
account,
profile,
});
return false;
}

if (account?.provider === "google" && profile?.email) {
console.log("Checking MongoDB for:", profile.email);
const response = await GetManyUsers({ email: profile.email });
console.log("MongoDB lookup result:", response);

if (!response.ok || response.body.length === 0) {
console.log(
`[NextAuth] Google login denied, user not found: ${profile.email}`
);
return false;
}

console.log(`[NextAuth] Google login allowed for: ${profile.email}`);
return true;
}

return true;
},
},
secret: process.env.AUTH_SECRET,
});