diff --git a/apps/client/package.json b/apps/client/package.json
index 76def19..f9c8db0 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -3,7 +3,7 @@
"version": "1.0.0",
"private": true,
"scripts": {
- "dev": "next dev --turbopack -p 3001",
+ "dev": "next dev --turbopack -p 3000",
"build": "next build",
"start": "next start",
"lint": "next lint"
@@ -34,6 +34,7 @@
"@mui/x-data-grid": "^8.14.1",
"@mui/x-date-pickers": "^8.14.1",
"axios": "^1.12.2",
+ "better-auth": "^1.3.34",
"clsx": "^2.1.1",
"dayjs": "^1.11.18",
"gsap": "^3.13.0",
diff --git a/apps/client/src/app/authentication/default/login/page.tsx b/apps/client/src/app/authentication/default/login/page.tsx
index 0f71830..6b7ad8d 100644
--- a/apps/client/src/app/authentication/default/login/page.tsx
+++ b/apps/client/src/app/authentication/default/login/page.tsx
@@ -1,17 +1,20 @@
'use client';
-import { signIn } from 'next-auth/react';
import LoginForm from 'components/sections/authentications/default/LoginForm';
-import paths from 'routes/paths';
-import { defaultJwtAuthCredentials } from 'config';
+import paths, { rootPaths } from 'routes/paths';
+import { authClient } from 'lib/auth-client';
+import { useRouter } from 'next/navigation';
const Page = () => {
- const handleLogin = async (data: { email: string; password: string }) => {
- return await signIn('credentials', {
- email: data.email,
- password: data.password,
- redirect: false,
- });
+ const router = useRouter()
+ const handleLogin = async (data: { email: string; password: string , rememberDevice: boolean }) => {
+ try {
+ const response = await authClient.signIn.email(data)
+ return response
+
+ } catch (error) {
+ return error
+ }
};
return (
@@ -21,7 +24,6 @@ const Page = () => {
forgotPasswordLink={paths.forgotPassword}
socialAuth={false}
rememberDevice={true}
- defaultCredential={defaultJwtAuthCredentials}
/>
);
};
diff --git a/apps/client/src/app/authentication/default/signup/page.tsx b/apps/client/src/app/authentication/default/signup/page.tsx
index 2635c1f..18b31c7 100644
--- a/apps/client/src/app/authentication/default/signup/page.tsx
+++ b/apps/client/src/app/authentication/default/signup/page.tsx
@@ -1,16 +1,22 @@
'use client';
-import { signIn } from 'next-auth/react';
+import { authClient } from 'lib/auth-client';
import SignupForm from 'components/sections/authentications/default/SignupForm';
const Page = () => {
const handleSignup = async (data: { name: string; email: string; password: string }) => {
- return await signIn('signup', {
- name: data.name,
- email: data.email,
- password: data.password,
- redirect: false,
- });
+
+ try {
+ const response = await authClient.signUp.email({
+ name: data.name,
+ email: data.email,
+ password: data.password,
+ });
+ return response;
+ } catch (error) {
+ console.error(error);
+ return error;
+ }
};
return ;
diff --git a/apps/client/src/components/sections/authentications/default/LoginForm.tsx b/apps/client/src/components/sections/authentications/default/LoginForm.tsx
index 168fa02..4baa90e 100644
--- a/apps/client/src/components/sections/authentications/default/LoginForm.tsx
+++ b/apps/client/src/components/sections/authentications/default/LoginForm.tsx
@@ -24,7 +24,7 @@ import DefaultCredentialAlert from '../common/DefaultCredentialAlert';
import SocialAuth from './SocialAuth';
interface LoginFormProps {
- handleLogin: (data: LoginFormValues) => Promise;
+ handleLogin: (data: LoginFormValues) => Promise;
signUpLink: string;
socialAuth?: boolean;
forgotPasswordLink?: string;
@@ -34,6 +34,7 @@ interface LoginFormProps {
export interface LoginFormValues {
email: string;
password: string;
+ rememberDevice: boolean;
}
const schema = yup
@@ -43,6 +44,7 @@ const schema = yup
.email('Please provide a valid email address.')
.required('This field is required'),
password: yup.string().required('This field is required'),
+ rememberDevice: yup.boolean().optional().default(false),
})
.required();
@@ -70,7 +72,7 @@ const LoginForm = ({
const onSubmit = async (data: LoginFormValues) => {
const res = await handleLogin(data);
- if (res?.ok) {
+ if (res?.data?.token) {
router.refresh();
router.push(callbackUrl ? callbackUrl : rootPaths.root);
}
@@ -193,8 +195,8 @@ const LoginForm = ({
}}
>
{rememberDevice && (
- }
+ }
label={
Promise;
+ handleSignup: (data: SignupFormValues) => Promise;
socialAuth?: boolean;
}
diff --git a/apps/client/src/lib/auth-client.ts b/apps/client/src/lib/auth-client.ts
new file mode 100644
index 0000000..016c82d
--- /dev/null
+++ b/apps/client/src/lib/auth-client.ts
@@ -0,0 +1,7 @@
+import { createAuthClient } from "better-auth/react"
+
+export const authClient = createAuthClient({
+ /** The base URL of the server (optional if you're using the same domain) */
+ baseURL: process.env.BETTER_AUTH_URL || "http://localhost:4000/api/auth",
+ fetchOptions: { credentials: 'include' },
+})
\ No newline at end of file
diff --git a/apps/server/.env.example b/apps/server/.env.example
index 5a17660..f25679c 100644
--- a/apps/server/.env.example
+++ b/apps/server/.env.example
@@ -21,4 +21,6 @@ STRIPE_SECRET_KEY=sk_test_
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
+TRUSTED_ORIGINS=http://localhost:3000
+
diff --git a/apps/server/auth.ts b/apps/server/auth.ts
index 78d64c7..9ff2d04 100644
--- a/apps/server/auth.ts
+++ b/apps/server/auth.ts
@@ -25,6 +25,7 @@ export const auth: AuthInstance = betterAuth({
transaction: true,
debugLogs: true,
}),
+ trustedOrigins: ['http://localhost:3000'],
// npx @better-auth/cli@latest generate
appName: 'Server',
plugins: [
diff --git a/apps/server/package.json b/apps/server/package.json
index 84c8398..57ec9b7 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -15,6 +15,7 @@
"nest": "nest",
"dev": "pnpm run start:dev",
"prisma:generate": "pnpx prisma generate",
+ "prisma:dev": "pnpx prisma migrate dev",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts
index 06d079d..d2c8b75 100644
--- a/apps/server/src/main.ts
+++ b/apps/server/src/main.ts
@@ -36,6 +36,7 @@ async function bootstrap() {
"'self'",
'https://cdn.jsdelivr.net',
'http://localhost:3000',
+ 'http://localhost:4000',
],
},
},
@@ -45,7 +46,17 @@ async function bootstrap() {
origin: corsConfig.origins,
credentials: corsConfig.credentials,
methods: corsConfig.methods,
- allowedHeaders: corsConfig.allowedHeaders,
+ // allowedHeaders: corsConfig.allowedHeaders,
+ allowedHeaders:
+ corsConfig.allowedHeaders.length > 0
+ ? corsConfig.allowedHeaders
+ : [
+ 'Content-Type',
+ 'Authorization',
+ 'X-Requested-With',
+ 'Accept',
+ 'Origin',
+ ],
});
app.useGlobalPipes(
new ValidationPipe({
@@ -72,7 +83,7 @@ async function bootstrap() {
const documentFactory = () => SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, documentFactory);
- // app.setGlobalPrefix('api');
+ app.setGlobalPrefix('api');
await app.listen(port);
Logger.debug(`Server started on http://localhost:${port}`);
Logger.debug(
diff --git a/package.json b/package.json
index 941ef62..ab9549f 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"dev:client": "pnpm --filter client dev",
"prebuild": "pnpm -r --filter server run prisma:generate",
"dev:server": "pnpm --filter server start:dev",
- "build:client": "pnpm --filter client build",
+ "build:client": "pnpm --filter client build",
+ "prisma:dev": "pnpm --filter server run prisma:dev",
"build:server": "pnpm --filter server build",
"start:client": "pnpm --filter client start",
"start:server": "pnpm --filter server start",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3fd5168..cf3300e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -99,6 +99,9 @@ importers:
axios:
specifier: ^1.12.2
version: 1.13.1
+ better-auth:
+ specifier: ^1.3.34
+ version: 1.3.34(next@15.5.6(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
clsx:
specifier: ^2.1.1
version: 2.1.1
@@ -246,7 +249,7 @@ importers:
version: 1.13.1
better-auth:
specifier: ^1.3.34
- version: 1.3.34
+ version: 1.3.34(next@15.5.6(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
cache-manager:
specifier: ^7.2.4
version: 7.2.4
@@ -6039,7 +6042,7 @@ snapshots:
'@better-auth/stripe@1.3.34(@better-auth/core@1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.0)(kysely@0.28.8)(nanostores@1.0.1))(better-auth@1.3.34)(stripe@19.2.0(@types/node@22.18.12))':
dependencies:
'@better-auth/core': 1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.0)(kysely@0.28.8)(nanostores@1.0.1)
- better-auth: 1.3.34
+ better-auth: 1.3.34(next@15.5.6(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
defu: 6.1.4
stripe: 19.2.0(@types/node@22.18.12)
zod: 4.1.12
@@ -7727,7 +7730,7 @@ snapshots:
'@nestjs/common': 11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/graphql': 13.2.0(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(class-transformer@0.5.1)(class-validator@0.14.2)(graphql@16.11.0)(reflect-metadata@0.2.2)
- better-auth: 1.3.34
+ better-auth: 1.3.34(next@15.5.6(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
express: 5.1.0
graphql: 16.11.0
typescript: 5.9.3
@@ -8422,7 +8425,7 @@ snapshots:
baseline-browser-mapping@2.8.18: {}
- better-auth@1.3.34:
+ better-auth@1.3.34(next@15.5.6(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
dependencies:
'@better-auth/core': 1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.0)(kysely@0.28.8)(nanostores@1.0.1)
'@better-auth/telemetry': 1.3.34(better-call@1.0.19)(jose@6.1.0)(kysely@0.28.8)(nanostores@1.0.1)
@@ -8438,6 +8441,10 @@ snapshots:
kysely: 0.28.8
nanostores: 1.0.1
zod: 4.1.12
+ optionalDependencies:
+ next: 15.5.6(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
better-call@1.0.19:
dependencies: