Create authentication#7
Conversation
… to accept users credentials compulsorily
| @@ -0,0 +1,4 @@ | |||
| export class LoginDto { | |||
| email: string; | |||
There was a problem hiding this comment.
Add validation, Is email for the email and is non empty string for the password
| @@ -0,0 +1,4 @@ | |||
| export class LoginDto { | |||
| email: string; | |||
There was a problem hiding this comment.
Add validation , Is Email for the email and Is non empty string for the password
| userType: user.userType, | ||
| }; | ||
|
|
||
| const token = jwt.sign(payload, env.JWT_SECRET || 'brjhjhjhghghghgkgkgkgk', { |
There was a problem hiding this comment.
Nope use a null operator, the string should ne defined else this should error out
| // 4. Return token and user info | ||
| return { | ||
| access_token: token, | ||
| user: { |
There was a problem hiding this comment.
More scalable to declare a user dto class with a respective toJSON function that you can use to hide sensitive or certain fields.
8adf517 to
157ab06
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces an authentication module for user login verification, along with a complete users module for user management. The implementation creates JWT-based authentication infrastructure with role-based access control (RBAC) for admin-only endpoints.
Changes:
- Created authentication module with login endpoint that validates credentials and returns JWT tokens
- Implemented users module with CRUD operations, role-based guards, and password validation
- Updated database schema to enforce non-null constraints on user fields
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| src/auth/auth.module.ts | Defines auth module structure, importing UsersModule for user data access |
| src/auth/auth.service.ts | Implements login logic with bcrypt password comparison and JWT token generation |
| src/auth/auth.controller.ts | Exposes POST /auth/login endpoint |
| src/auth/dto/login.dto.ts | Defines login request structure (email and password) |
| src/users/users.module.ts | Configures users module with service, repository, and guards |
| src/users/users.service.ts | Provides business logic for user operations including admin check |
| src/users/users.repository.ts | Database access layer for user CRUD operations using Drizzle ORM |
| src/users/users.controller.ts | REST endpoints for user creation and admin-only user listing |
| src/users/roles.guard.ts | Authorization guard that checks user roles from JWT payload |
| src/users/roles.decorator.ts | Metadata decorator for specifying required roles on endpoints |
| src/users/dto/users-dto.ts | Validates user creation with strong password requirements |
| src/db/schema.ts | Adds non-null constraints to user table fields |
| src/config/env.ts | Adds JWT_SECRET environment variable |
| package.json | Adds bcrypt and jsonwebtoken dependencies |
| src/app.module.ts | Registers AuthModule in application |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
|
|
||
|
|
||
| @Controller('users') | ||
| export class UsersController { | ||
| constructor(private readonly usersService: UsersService) {} | ||
|
|
||
| @Post() | ||
| async create(@Body() createUserDto: CreateUserDto) { | ||
| return this.usersService.create(createUserDto); |
There was a problem hiding this comment.
Passwords are being stored in plaintext without hashing. The CreateUserDto accepts a passwordHash field, but there's no hashing logic before saving to the database. Users created through this endpoint will have their passwords stored in plaintext, which is a critical security vulnerability. You should hash the password using bcrypt before storing it in the repository.
| @Controller('users') | |
| export class UsersController { | |
| constructor(private readonly usersService: UsersService) {} | |
| @Post() | |
| async create(@Body() createUserDto: CreateUserDto) { | |
| return this.usersService.create(createUserDto); | |
| import * as bcrypt from 'bcrypt'; | |
| @Controller('users') | |
| export class UsersController { | |
| constructor(private readonly usersService: UsersService) {} | |
| @Post() | |
| async create(@Body() createUserDto: CreateUserDto) { | |
| const hashedPassword = await bcrypt.hash(createUserDto.passwordHash, 10); | |
| const createUserWithHashedPassword: CreateUserDto = { | |
| ...createUserDto, | |
| passwordHash: hashedPassword, | |
| }; | |
| return this.usersService.create(createUserWithHashedPassword); |
| @Injectable() | ||
| export class AuthService { | ||
| constructor(private readonly usersRepository: UsersRepository) {} | ||
|
|
||
| async login(loginDto: LoginDto) { |
There was a problem hiding this comment.
Missing return type annotation. The method should explicitly return Promise<any> or a properly typed response DTO to improve code clarity and type safety.
| @Injectable() | |
| export class AuthService { | |
| constructor(private readonly usersRepository: UsersRepository) {} | |
| async login(loginDto: LoginDto) { | |
| interface AuthenticatedUser { | |
| id: any; | |
| name: string; | |
| email: string; | |
| userType: any; | |
| } | |
| interface LoginResponse { | |
| access_token: string; | |
| user: AuthenticatedUser; | |
| } | |
| @Injectable() | |
| export class AuthService { | |
| constructor(private readonly usersRepository: UsersRepository) {} | |
| async login(loginDto: LoginDto): Promise<LoginResponse> { |
| passwordHash: text('password_hash'), | ||
|
|
||
| userType: mysqlEnum('user_type', UserType).notNull() | ||
| .default(UserType.USER), // ADMIN or USER sert to user by default |
There was a problem hiding this comment.
Typo in comment: "sert" should be "set".
| .default(UserType.USER), // ADMIN or USER sert to user by default | |
| .default(UserType.USER), // ADMIN or USER set to user by default |
| import { UsersRepository } from 'src/users/users.repository'; | ||
| import * as bcrypt from 'bcrypt'; | ||
| import * as jwt from 'jsonwebtoken'; | ||
| import { env } from 'src/config/env'; |
There was a problem hiding this comment.
Inconsistent import path style. Use relative imports like '../users/users.repository' and '../config/env' instead of 'src/' absolute paths to match the codebase conventions.
| import { UsersRepository } from 'src/users/users.repository'; | |
| import * as bcrypt from 'bcrypt'; | |
| import * as jwt from 'jsonwebtoken'; | |
| import { env } from 'src/config/env'; | |
| import { UsersRepository } from '../users/users.repository'; | |
| import * as bcrypt from 'bcrypt'; | |
| import * as jwt from 'jsonwebtoken'; | |
| import { env } from '../config/env'; |
| export class LoginDto { | ||
| email: string; | ||
| password: string; | ||
| } No newline at end of file |
There was a problem hiding this comment.
The LoginDto lacks validation decorators. Email and password should be validated using class-validator decorators (@isemail, @isnotempty, @IsString) to ensure proper input validation and security. This is inconsistent with the CreateUserDto pattern used elsewhere in the codebase.
| import { CreateUserDto } from './dto/users-dto'; | ||
| import { RolesGuard } from './roles.guard'; | ||
| import { Roles } from './roles.decorator'; | ||
| import { UserType } from 'src/transactions/transactions.types'; |
There was a problem hiding this comment.
Inconsistent import path style. This file uses 'src/transactions/transactions.types' while other files in the users module use '../' relative imports. For consistency, use relative imports like '../transactions/transactions.types' to match the pattern used in users.service.ts line 4.
| import { UserType } from 'src/transactions/transactions.types'; | |
| import { UserType } from '../transactions/transactions.types'; |
| @@ -0,0 +1,5 @@ | |||
| import { SetMetadata } from '@nestjs/common'; | |||
| import { UserType } from 'src/transactions/transactions.types'; | |||
There was a problem hiding this comment.
Inconsistent import path style. Use relative imports '../transactions/transactions.types' instead of 'src/transactions/transactions.types' to match the pattern in users.service.ts line 4.
| import { UserType } from 'src/transactions/transactions.types'; | |
| import { UserType } from '../transactions/transactions.types'; |
| @@ -0,0 +1,18 @@ | |||
| import { Module } from '@nestjs/common'; | |||
| import { UsersService } from './users.service'; | |||
| import { DbModule } from 'src/db/db.module'; | |||
There was a problem hiding this comment.
Inconsistent import path style. Use relative import '../db/db.module' instead of 'src/db/db.module' to match the codebase conventions.
| import { DbModule } from 'src/db/db.module'; | |
| import { DbModule } from '../db/db.module'; |
| export class UsersController { | ||
| constructor(private readonly usersService: UsersService) {} | ||
|
|
||
| @Post() |
There was a problem hiding this comment.
The user creation endpoint is completely unprotected - anyone can create users with any userType (including ADMIN). This is a critical security vulnerability. Either this endpoint should be publicly accessible for registration (in which case userType should always be USER and not accepted from input), or it should be protected with admin-only authentication.
| @Post() | |
| @Post() | |
| @UseGuards(RolesGuard) | |
| @Roles(UserType.ADMIN) |
|
|
||
| imports: [DbModule], | ||
| controllers: [UsersController], | ||
| exports: [UsersRepository], |
There was a problem hiding this comment.
UsersService should be exported from UsersModule since it's used by the AuthService. The auth module imports UsersModule but only UsersRepository is currently exported. This will cause a runtime dependency injection error when AuthService tries to access user functionality beyond repository methods (like the isAdmin method).
| exports: [UsersRepository], | |
| exports: [UsersRepository, UsersService], |
##What i did:
Created the Auth module for login verification.