Search code examples
nestjsnestjs-passportnestjs-jwt

NestJS empty JWT token


A new user is created without a jwt token. An empty token is returned

I don't understand what the problem is. Help me please. Himself frontend developer and backend for study. Don't scold too much) https://github.com/theDeemoonn/reex-backend

Service

import {
  Injectable,
  HttpException,
  HttpStatus,
  UnauthorizedException,
} from '@nestjs/common';
import { UsersService } from '../users/users.service';
import { CreateUserDto } from '../users/dto/create-user.dto';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcryptjs';
import { User } from '../users/users.model';

@Injectable()
export class AuthService {
  constructor(
    private userService: UsersService,
    private JwtService: JwtService,
  ) {}
  async login(userDto: CreateUserDto) {
    const user = await this.validateUser(userDto);
    const tokens = await this.issueTokenPair(user);
    return {
      user: this.returnUserFields(user),
      ...tokens,
    };
  }
  async registration(userDto: CreateUserDto) {
    const candidate = await this.userService.getUserByEmail(userDto.email);
    if (candidate) {
      throw new HttpException(
        'Пользователь с таким email уже существует',
        HttpStatus.BAD_REQUEST,
      );
    }
    const hashPassword = await bcrypt.hash(userDto.password, 6);
    const user = await this.userService.createUser({
      ...userDto,
      password: hashPassword,
    });
    const newUser = await user.save();
    const tokens = await this.issueTokenPair(newUser);
    return { user: this.returnUserFields(user), ...tokens };
  }

  private async validateUser(userDto: CreateUserDto) {
    const user = await this.userService.getUserByEmail(userDto.email);
    const passwordEquals = await bcrypt.compare(
      userDto.password,
      user.password,
    );
    if (!passwordEquals) {
      throw new UnauthorizedException('Некорректный пароль');
    }
    if (user && passwordEquals) {
      return user;
    }
    throw new UnauthorizedException('Некорректный email или пароль');
  }

  private async issueTokenPair(user: User) {
    const payload = { email: user.email, id: user.id, roles: user.roles };
    const refreshToken = await this.JwtService.signAsync(payload, {
      expiresIn: '15d',
    });
    const accessToken = await this.JwtService.signAsync(payload, {
      expiresIn: '1h',
    });
    return { refreshToken, accessToken };
  }
  returnUserFields(user: User) {
    return {
      _id: user.id,
      email: user.email,
    };
  }
}

Controller

import {
  Body,
  Controller,
  Post,
  UsePipes,
  ValidationPipe,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { CreateUserDto } from '../users/dto/create-user.dto';
import { AuthService } from './auth.service';
@ApiTags('Авторизация')
@Controller('auth')
export class AuthController {
  constructor(private authService: AuthService) {}
  @UsePipes(new ValidationPipe())
  @Post('/login')
  async login(@Body() userDto: CreateUserDto) {
    await this.authService.login(userDto);
  }
  @UsePipes(new ValidationPipe())
  @Post('/registration')
  async registration(@Body() userDto: CreateUserDto) {
    await this.authService.registration(userDto);
  }
}

Module

import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from './strategy/jwt.strategy';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { getJWTConfig } from './config/jwt.config';

@Module({
  controllers: [AuthController],
  providers: [AuthService, JwtStrategy],
  imports: [
    UsersModule,
    ConfigModule,
    JwtModule.registerAsync({
      imports: [ConfigModule],
      useFactory: getJWTConfig,
      inject: [ConfigService],
    }),
  ],
})
export class AuthModule {}

JwtStrategy I thought that the problem was in .env wrote secretOrKey: ${process.env.SECRET_KEY} did not work

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { User } from '../../users/users.model';
import { UsersService } from '../../users/users.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    private readonly configService: ConfigService,
    private readonly usersService: UsersService,
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: `${process.env.SECRET_KEY}`,
    });
  }

  async validate(users: User) {
    return await this.usersService.getUserById(users.id);
  }
}

JWTConfig

import { ConfigService } from '@nestjs/config';
import { JwtModuleOptions } from '@nestjs/jwt';

export const getJWTConfig = async (
  configService: ConfigService,
): Promise<JwtModuleOptions> => ({
  secret: configService.get('SECRET_KEY'),
});

CreateUserDto

import { ApiProperty } from '@nestjs/swagger';
import { IsEmail, IsString, MinLength } from 'class-validator';

export class CreateUserDto {
  @ApiProperty({ example: '[email protected]', description: 'Почта' })
  @IsEmail({}, { message: 'Некорректный email' })
  readonly email: string;
  @ApiProperty({ example: 'qwerty123456', description: 'Пароль' })
  @MinLength(6, { message: 'Пароль должен быть больше 6 символов' })
  @IsString()
  readonly password: string;
  @ApiProperty({ example: 'Иванов', description: 'Фамилия' })
  readonly surname: string;
  @ApiProperty({ example: 'Иван', description: 'Имя' })
  readonly name: string;
  @ApiProperty({ example: '20', description: 'Возраст' })
  readonly age: number;
  @ApiProperty({ example: '89999999999', description: 'Телефон' })
  readonly phone: number;
}

postman request


Solution

  • You aren't returning anything in your controller, so the post succeeds but has nothing to send back to the client. Add return before your await this.service. whatever method calls