Skip to content

Commit f6ad765

Browse files
committed
fix: implement password hashing and verification for user registration
1 parent ec52702 commit f6ad765

File tree

4 files changed

+36
-20
lines changed

4 files changed

+36
-20
lines changed

examples/demos/dashboard-integration/init-databases.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,16 @@ CREATE TABLE users
6464
email VARCHAR(255) NOT NULL UNIQUE,
6565
"emailVerified" TIMESTAMPTZ,
6666
image TEXT,
67+
hashed_password TEXT,
6768
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
6869
"updatedAt" TIMESTAMPTZ DEFAULT NOW(),
6970

7071
PRIMARY KEY (id)
7172
);
7273

74+
-- Create index on email for faster lookups
75+
CREATE INDEX idx_users_email ON users (email);
76+
7377
-- Connect to outpost database to set up schema permissions
7478
\c outpost;
7579
GRANT ALL ON SCHEMA public TO outpost;

examples/demos/dashboard-integration/src/app/api/auth/register/route.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { NextRequest, NextResponse } from "next/server";
2+
import bcrypt from "bcryptjs";
23
import { createUser, getUserByEmail } from "../../../../lib/db";
34
import { createTenant } from "../../../../lib/outpost";
45
import { generateTenantId } from "../../../../lib/utils";
@@ -15,14 +16,18 @@ export async function POST(request: NextRequest) {
1516
if (existingUser) {
1617
return NextResponse.json(
1718
{ message: "User already exists" },
18-
{ status: 400 },
19+
{ status: 400 }
1920
);
2021
}
2122

22-
// Create user in database
23+
// Hash the password before storing
24+
const hashedPassword = await bcrypt.hash(validatedData.password, 12);
25+
26+
// Create user in database with hashed password
2327
const user = await createUser({
2428
email: validatedData.email,
2529
name: validatedData.name,
30+
hashedPassword,
2631
});
2732

2833
// Create tenant in Outpost using the user ID
@@ -41,7 +46,7 @@ export async function POST(request: NextRequest) {
4146
userId: user.id,
4247
tenantId,
4348
email: validatedData.email,
44-
},
49+
}
4550
);
4651
} catch (outpostError) {
4752
logger.error("Failed to create Outpost tenant during registration", {
@@ -56,7 +61,7 @@ export async function POST(request: NextRequest) {
5661

5762
return NextResponse.json(
5863
{ message: "User created successfully" },
59-
{ status: 201 },
64+
{ status: 201 }
6065
);
6166
} catch (error: any) {
6267
logger.error("Registration error", { error, errorMessage: error?.message });
@@ -65,13 +70,13 @@ export async function POST(request: NextRequest) {
6570
// Validation error
6671
return NextResponse.json(
6772
{ message: "Validation failed", errors: error.errors },
68-
{ status: 400 },
73+
{ status: 400 }
6974
);
7075
}
7176

7277
return NextResponse.json(
7378
{ message: "Internal server error" },
74-
{ status: 500 },
79+
{ status: 500 }
7580
);
7681
}
7782
}

examples/demos/dashboard-integration/src/lib/auth.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,18 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
2525
return null;
2626
}
2727

28-
// For demo purposes, we'll skip password verification
29-
// In a real app, you'd verify the hashed password here
30-
// const isPasswordValid = await bcrypt.compare(credentials.password as string, user.hashedPassword)
31-
// if (!isPasswordValid) {
32-
// return null
33-
// }
28+
// Verify the password against the hashed password
29+
if (!user.hashedPassword) {
30+
return null;
31+
}
32+
33+
const isPasswordValid = await bcrypt.compare(
34+
credentials.password as string,
35+
user.hashedPassword
36+
);
37+
if (!isPasswordValid) {
38+
return null;
39+
}
3440

3541
return {
3642
id: user.id.toString(),

examples/demos/dashboard-integration/src/lib/db.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ export interface User {
1414
email: string;
1515
emailVerified?: Date | null;
1616
image?: string | null;
17+
hashedPassword?: string | null;
1718
createdAt: Date;
1819
updatedAt: Date;
1920
}
2021

2122
export async function getUserTenant(userId: string): Promise<User | null> {
2223
try {
2324
const result = await pool.query(
24-
'SELECT id, name, email, "emailVerified", image, "createdAt", "updatedAt" FROM users WHERE id = $1',
25-
[userId],
25+
'SELECT id, name, email, "emailVerified", image, hashed_password as "hashedPassword", "createdAt", "updatedAt" FROM users WHERE id = $1',
26+
[userId]
2627
);
2728
return result.rows[0] || null;
2829
} catch (error) {
@@ -38,10 +39,10 @@ export async function createUser(userData: {
3839
}): Promise<User> {
3940
try {
4041
const result = await pool.query(
41-
`INSERT INTO users (email, name, "createdAt", "updatedAt")
42-
VALUES ($1, $2, NOW(), NOW())
43-
RETURNING id, name, email, "emailVerified", image, "createdAt", "updatedAt"`,
44-
[userData.email, userData.name || null],
42+
`INSERT INTO users (email, name, hashed_password, "createdAt", "updatedAt")
43+
VALUES ($1, $2, $3, NOW(), NOW())
44+
RETURNING id, name, email, "emailVerified", image, hashed_password as "hashedPassword", "createdAt", "updatedAt"`,
45+
[userData.email, userData.name || null, userData.hashedPassword || null]
4546
);
4647
const newUser = result.rows[0];
4748
logger.info("User created successfully", {
@@ -58,8 +59,8 @@ export async function createUser(userData: {
5859
export async function getUserByEmail(email: string): Promise<User | null> {
5960
try {
6061
const result = await pool.query(
61-
'SELECT id, name, email, "emailVerified", image, "createdAt", "updatedAt" FROM users WHERE email = $1',
62-
[email],
62+
'SELECT id, name, email, "emailVerified", image, hashed_password as "hashedPassword", "createdAt", "updatedAt" FROM users WHERE email = $1',
63+
[email]
6364
);
6465
return result.rows[0] || null;
6566
} catch (error) {

0 commit comments

Comments
 (0)