diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 8fb60a0..5f74c0e 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -1,17 +1,19 @@ -import { Controller, Post } from '@nestjs/common'; +import { Controller, Post, Body, HttpCode, HttpStatus } from '@nestjs/common'; import { AuthService } from './auth.service'; +import { AuthDto } from './dto'; @Controller('auth') export class AuthController { constructor(private authService: AuthService) {} @Post('signup') - signup() { - return this.authService.signup(); + signup(@Body() dto: AuthDto) { + return this.authService.signup(dto); } + @HttpCode(HttpStatus.OK) @Post('signin') - signin() { - return this.authService.signin(); + signin(@Body() dto: AuthDto) { + return this.authService.signin(dto); } } diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index a7d9fbc..6cc6f73 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -1,9 +1,12 @@ import { Module } from '@nestjs/common'; +import { JwtModule } from '@nestjs/jwt'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; +import { JwtStrategy } from './strategy'; @Module({ + imports: [JwtModule.register({})], controllers: [AuthController], - providers: [AuthService], + providers: [AuthService, JwtStrategy], }) export class AuthModule {} diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index b97fe4e..17f0bea 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -1,12 +1,78 @@ -import { Injectable } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { ForbiddenException, Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { AuthDto } from './dto'; +import * as argon from 'argon2'; +import { PrismaClientKnownRequestError } from '@prisma/client/runtime'; +import { ConfigService } from '@nestjs/config'; -@Injectable({}) +@Injectable() export class AuthService { - signup() { - return { msg: 'I am signed up' }; + constructor( + private prisma: PrismaService, + private jwt: JwtService, + private config: ConfigService, + ) {} + + async signup(dto: AuthDto) { + // generate the password hash + const hash = await argon.hash(dto.password); + try { + // save the new user in the db + const user = await this.prisma.user.create({ + data: { + email: dto.email, + hash, + }, + }); + // return jwt token + return this.signToken(user.id, user.email); + } catch (error) { + if (error instanceof PrismaClientKnownRequestError) { + if (error.code === 'P2002') { + throw new ForbiddenException('Credentials Taken'); + } + } + + throw error; + } + } + + async signin(dto: AuthDto) { + // find the user by email + const user = await this.prisma.user.findUnique({ + where: { + email: dto.email, + }, + }); + // if user does not exits throw exception + if (!user) throw new ForbiddenException('Credentials incorrect'); + // compare password + const pwMatches = await argon.verify(user.hash, dto.password); + // if password incorrect throw exception + if (!pwMatches) throw new ForbiddenException('Credentials incorrect'); + // return jwt token + return this.signToken(user.id, user.email); } - signin() { - return { msg: 'I am signed in' }; + async signToken( + userId: number, + email: string, + ): Promise<{ access_token: string }> { + const payload = { + sub: userId, + email, + }; + + const secret = this.config.get('JWT_SECRET'); + + const token = await this.jwt.signAsync(payload, { + expiresIn: '15m', + secret: secret, + }); + + return { + access_token: token, + }; } }