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
77 changes: 77 additions & 0 deletions lib/auth/authService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { describe, it, expect } from 'vitest';
import { authService } from './authService';

describe('Authentication Service', () => {
it('should register a new user', async () => {
const result = await authService.register({
email: '[email protected]',
password: 'password123',
confirmPassword: 'password123'
});

expect(result.success).toBe(true);
expect(result.user?.email).toBe('[email protected]');
expect(result.token).toBeTruthy();
});

it('should not register a user with mismatched passwords', async () => {
const result = await authService.register({
email: '[email protected]',
password: 'password123',
confirmPassword: 'differentpassword'
});

expect(result.success).toBe(false);
expect(result.message).toBe('Passwords do not match');
});

it('should not register a user with existing email', async () => {
await authService.register({
email: '[email protected]',
password: 'password123',
confirmPassword: 'password123'
});

const result = await authService.register({
email: '[email protected]',
password: 'password456',
confirmPassword: 'password456'
});

expect(result.success).toBe(false);
expect(result.message).toBe('User already exists');
});

it('should login a registered user', async () => {
await authService.register({
email: '[email protected]',
password: 'password123',
confirmPassword: 'password123'
});

const result = await authService.login({
email: '[email protected]',
password: 'password123'
});

expect(result.success).toBe(true);
expect(result.user?.email).toBe('[email protected]');
expect(result.token).toBeTruthy();
});

it('should not login with incorrect password', async () => {
await authService.register({
email: '[email protected]',
password: 'password123',
confirmPassword: 'password123'
});

const result = await authService.login({
email: '[email protected]',
password: 'wrongpassword'
});

expect(result.success).toBe(false);
expect(result.message).toBe('Invalid email or password');
});
});
90 changes: 90 additions & 0 deletions lib/auth/authService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { LoginCredentials, RegisterCredentials, AuthResponse, User } from '../../types/auth';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';

const JWT_SECRET = process.env.JWT_SECRET || 'fallback_secret';
const SALT_ROUNDS = 10;

// In-memory user store (replace with database in production)
const users: User[] = [];

export const authService = {
async register(credentials: RegisterCredentials): Promise<AuthResponse> {
const { email, password, confirmPassword } = credentials;

// Validate inputs
if (!email || !password) {
return { success: false, message: 'Email and password are required' };
}

if (password !== confirmPassword) {
return { success: false, message: 'Passwords do not match' };
}

// Check if user already exists
const existingUser = users.find(u => u.email === email);
if (existingUser) {
return { success: false, message: 'User already exists' };
}

// Hash password
const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);

// Create user
const newUser: User = {
id: Date.now().toString(),
email,
password: hashedPassword,
createdAt: new Date(),
updatedAt: new Date()
};

users.push(newUser);

// Generate token
const token = jwt.sign({ id: newUser.id, email: newUser.email }, JWT_SECRET, { expiresIn: '1h' });

return {
success: true,
message: 'User registered successfully',
user: {
id: newUser.id,
email: newUser.email,
createdAt: newUser.createdAt,
updatedAt: newUser.updatedAt
},
token
};
},

async login(credentials: LoginCredentials): Promise<AuthResponse> {
const { email, password } = credentials;

// Find user
const user = users.find(u => u.email === email);
if (!user) {
return { success: false, message: 'Invalid email or password' };
}

// Check password
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return { success: false, message: 'Invalid email or password' };
}

// Generate token
const token = jwt.sign({ id: user.id, email: user.email }, JWT_SECRET, { expiresIn: '1h' });

return {
success: true,
message: 'Login successful',
user: {
id: user.id,
email: user.email,
createdAt: user.createdAt,
updatedAt: user.updatedAt
},
token
};
}
};
Loading