Cannot hash the user's password with Prisma middleware in Nestjs on create User API request

Viewed 3059

I want to hash the user's password on create API with Prisma middleware, but it does not work. I create a separate ts file for Prisma middleware and import it into the main.ts file.

here is my code:

Prisma Middleware:

import { Prisma, PrismaClient } from '@prisma/client';
import * as bcrypt from 'bcrypt';

export function passwordMiddleware() {
  const prisma: PrismaClient = new PrismaClient();

  prisma.$use(async (params: Prisma.MiddlewareParams, next) => {
    if (params.action == 'create' && params.model == 'User') {
      const user = params.args.data;
      const salt = bcrypt.genSaltSync(10);
      const hash = bcrypt.hashSync(user.password, salt);
      user.password = hash;
      params.args.data = user;
    }
    return await next(params);
  });
}

main.ts file:

import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';

import { AppModule } from './app/app.module';
import { passwordMiddleware } from './app/core/prisma/middleware';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const globalPrefix = 'api';
  app.setGlobalPrefix(globalPrefix);
  const port = process.env.PORT || 3333;
  //******** Start Prisma Middlewares ********
  passwordMiddleware();
  //******** End Prisma Middlewares ********
  await app.listen(port, () => {
    Logger.log('Listening at http://localhost:' + port + '/' + globalPrefix);
  });
}

bootstrap();

Prisma Model:

model User {
  id         String      @id @default(uuid())
  email      String      @unique
  password   String
  name       String?
  gender     String?
  address    String?
  telecom    String?
  birthDate  DateTime?
  createdAt DateTime @default(now())
}

Auth Controller:

  @Post('register')
  register(@Body() registerDto: RegisterDto) {
    return this.authService.register(registerDto);
  }

Auth Service:

register(registerDto: RegisterDto): Promise<User> {
    return this.prismaService.user.create({
      data: {
        email: registerDto.email,
        password: registerDto.password,
      },
    });
  }
3 Answers

You applying middleware to the express itself and you should apply middleware to prisma client in the PrismaService onModuleInit method, i e:

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {

  async onModuleInit() {
    await this.$connect();
    this.$use(async (params, next) => {
      if (params.action == 'create' && params.model == 'User') {
        const user = params.args.data;
        const salt = bcrypt.genSaltSync(10);
        const hash = bcrypt.hashSync(user.password, salt);
        user.password = hash;
        params.args.data = user;
      }
      return next(params);
    });
  }

In the end you do not change the returned params. Try adding: params.args.data = user; after hashing password.

Are you using the same PrismaClient that you use for your queries?

It seems in the passwordMiddleware method, you are doing this:

const prisma: PrismaClient = new PrismaClient();

This will create a new instance of PrismaClient and middleware would only work on this specific instance.

You need the same instance that you use for querying to register the middleware.

Related