From 1897f08674890ba0493d3fe6464547e39680ec8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Peveri?= Date: Mon, 27 Nov 2023 19:41:14 +0100 Subject: [PATCH 1/2] Add refresh token --- .../infrastructure/nestjs/controllers.ts | 2 ++ .../controllers/auth/loginPostController.ts | 2 ++ .../controllers/auth/loginPostResponseDto.ts | 5 +++ .../auth/refreshTokenPostController.ts | 35 +++++++++++++++++++ .../controllers/auth/refreshTokenPostDto.ts | 9 +++++ .../auth/refreshTokenPostResponseDto.ts | 9 +++++ 6 files changed, 62 insertions(+) create mode 100644 src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostController.ts create mode 100644 src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostDto.ts create mode 100644 src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostResponseDto.ts diff --git a/src/languages/infrastructure/nestjs/controllers.ts b/src/languages/infrastructure/nestjs/controllers.ts index cb791b2b..998b76bf 100644 --- a/src/languages/infrastructure/nestjs/controllers.ts +++ b/src/languages/infrastructure/nestjs/controllers.ts @@ -6,9 +6,11 @@ import ExpressionPostController from '../ui/api/v1/controllers/expressions/expre import CountriesGetController from '../ui/api/v1/controllers/countries/countriesGetController'; import CountryGetController from '../ui/api/v1/controllers/countries/countryGetController'; import CountryPostController from '../ui/api/v1/controllers/countries/countryPostController'; +import RefreshTokenPostController from '../ui/api/v1/controllers/auth/refreshTokenPostController'; export const controllers = [ LoginPostController, + RefreshTokenPostController, MeGetController, SearchTermsGetController, WordPostController, diff --git a/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostController.ts b/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostController.ts index c0bd5300..02f8f649 100644 --- a/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostController.ts +++ b/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostController.ts @@ -25,10 +25,12 @@ export default class LoginPostController { const user = { id: id, name: payload.name, email: payload.email }; const token: string = this.jwtService.sign(user); + const refreshToken: string = this.jwtService.sign(payload, { expiresIn: '30d' }); return { user, token, + refreshToken, }; } } diff --git a/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostResponseDto.ts b/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostResponseDto.ts index 8adefceb..40bbfb49 100644 --- a/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostResponseDto.ts +++ b/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostResponseDto.ts @@ -27,4 +27,9 @@ export default class LoginPostResponseDto { @IsNotEmpty() @IsString() token: string; + + @ApiProperty() + @IsNotEmpty() + @IsString() + refreshToken: string; } diff --git a/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostController.ts b/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostController.ts new file mode 100644 index 00000000..54f612e3 --- /dev/null +++ b/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostController.ts @@ -0,0 +1,35 @@ +import { Body, Controller, HttpCode, Inject, Post } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import LoginPostResponseDto from './loginPostResponseDto'; +import { ApiBadRequestResponse, ApiInternalServerErrorResponse, ApiOkResponse, ApiTags } from '@nestjs/swagger'; +import RefreshTokenPostDto from './refreshTokenPostDto'; +import RefreshTokenPostResponseDto from './refreshTokenPostResponseDto'; +import { QUERY_BUS, QueryBus } from '@src/shared/domain/buses/queryBus/queryBus'; +import FindUserQuery from '@src/languages/application/user/query/find/findUserQuery'; + +@ApiTags('Auth') +@Controller() +export default class RefreshTokenPostController { + public constructor(@Inject(QUERY_BUS) private queryBus: QueryBus, private jwtService: JwtService) {} + + @Post('auth/refresh-token') + @HttpCode(200) + @ApiOkResponse({ type: LoginPostResponseDto }) + @ApiBadRequestResponse({ description: 'Bad Request.' }) + @ApiInternalServerErrorResponse({ description: 'Internal Server Error.' }) + async run(@Body() payload: RefreshTokenPostDto): Promise { + const decodedRefreshToken = this.jwtService.verify(payload.refreshToken); + if (decodedRefreshToken.revoked) { + throw new Error('Token revoked'); + } + + await this.queryBus.ask(new FindUserQuery(decodedRefreshToken.sub)); + const user = await this.queryBus.ask(decodedRefreshToken.sub); + + const refreshToken = this.jwtService.sign(user); + + return { + refreshToken, + }; + } +} diff --git a/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostDto.ts b/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostDto.ts new file mode 100644 index 00000000..9656a23c --- /dev/null +++ b/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostDto.ts @@ -0,0 +1,9 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString } from 'class-validator'; + +export default class RefreshTokenPostDto { + @ApiProperty() + @IsNotEmpty() + @IsString() + refreshToken: string; +} diff --git a/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostResponseDto.ts b/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostResponseDto.ts new file mode 100644 index 00000000..66498250 --- /dev/null +++ b/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostResponseDto.ts @@ -0,0 +1,9 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString } from 'class-validator'; + +export default class RefreshTokenPostResponseDto { + @ApiProperty() + @IsNotEmpty() + @IsString() + refreshToken: string; +} From 7be26ac6e049a4bf0ffd64760a18aa9dc1889df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Peveri?= Date: Tue, 28 Nov 2023 21:44:40 +0100 Subject: [PATCH 2/2] Fix refresh token controller --- .../ui/api/v1/controllers/auth/loginPostController.ts | 2 +- .../api/v1/controllers/auth/refreshTokenPostController.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostController.ts b/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostController.ts index 02f8f649..c2b42f14 100644 --- a/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostController.ts +++ b/src/languages/infrastructure/ui/api/v1/controllers/auth/loginPostController.ts @@ -25,7 +25,7 @@ export default class LoginPostController { const user = { id: id, name: payload.name, email: payload.email }; const token: string = this.jwtService.sign(user); - const refreshToken: string = this.jwtService.sign(payload, { expiresIn: '30d' }); + const refreshToken: string = this.jwtService.sign(user, { expiresIn: '30d' }); return { user, diff --git a/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostController.ts b/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostController.ts index 54f612e3..67616706 100644 --- a/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostController.ts +++ b/src/languages/infrastructure/ui/api/v1/controllers/auth/refreshTokenPostController.ts @@ -23,10 +23,8 @@ export default class RefreshTokenPostController { throw new Error('Token revoked'); } - await this.queryBus.ask(new FindUserQuery(decodedRefreshToken.sub)); - const user = await this.queryBus.ask(decodedRefreshToken.sub); - - const refreshToken = this.jwtService.sign(user); + const user = await this.queryBus.ask(new FindUserQuery(decodedRefreshToken.id)); + const refreshToken = this.jwtService.sign(user.content); return { refreshToken,