feat: add refresh, logout methods
This commit is contained in:
parent
2b861c220a
commit
cce2d83101
@ -32,6 +32,7 @@
|
||||
"@teacinema/contracts": "^1.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.3",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
@ -42,6 +43,7 @@
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.1",
|
||||
"@teacinema/core": "1.0.7",
|
||||
"@types/cookie-parser": "^1.4.10",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^22.10.7",
|
||||
|
||||
@ -2,6 +2,7 @@ import { Logger } from '@nestjs/common'
|
||||
import { ConfigService } from '@nestjs/config'
|
||||
import { NestFactory } from '@nestjs/core'
|
||||
import { SwaggerModule } from '@nestjs/swagger'
|
||||
import cookieParser from 'cookie-parser'
|
||||
|
||||
import { AppModule } from './core/app.module'
|
||||
import { getCorsConfig, swaggerConfig, validationPipe } from './core/config'
|
||||
@ -13,6 +14,8 @@ async function bootstrap() {
|
||||
const logger = new Logger()
|
||||
const config = app.get(ConfigService)
|
||||
|
||||
app.use(cookieParser(config.getOrThrow<string>('COOKIES_SECRET')))
|
||||
|
||||
app.useGlobalPipes(validationPipe)
|
||||
app.useGlobalFilters(new GrpcExceptionFilter())
|
||||
|
||||
|
||||
@ -1,12 +1,26 @@
|
||||
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Post,
|
||||
Req,
|
||||
Res
|
||||
} from '@nestjs/common'
|
||||
import { ConfigService } from '@nestjs/config'
|
||||
import { ApiOperation } from '@nestjs/swagger'
|
||||
import type { Request, Response } from 'express'
|
||||
import { lastValueFrom } from 'rxjs'
|
||||
|
||||
import { AuthClientGrpc } from './auth.grpc'
|
||||
import { SendOtpRequestDto, VerifyOtpRequestDto } from './dto'
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private readonly client: AuthClientGrpc) {}
|
||||
constructor(
|
||||
private readonly client: AuthClientGrpc,
|
||||
private readonly config: ConfigService
|
||||
) {}
|
||||
|
||||
@ApiOperation({
|
||||
summary: 'Send OTP',
|
||||
@ -24,7 +38,60 @@ export class AuthController {
|
||||
})
|
||||
@Post('otp/verify')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
public verifyOtp(@Body() dto: VerifyOtpRequestDto) {
|
||||
return this.client.verifyOtp(dto)
|
||||
public async verifyOtp(
|
||||
@Body() dto: VerifyOtpRequestDto,
|
||||
@Res({ passthrough: true }) res: Response
|
||||
) {
|
||||
const { accessToken, refreshToken } = await lastValueFrom(
|
||||
this.client.verifyOtp(dto)
|
||||
)
|
||||
|
||||
res.cookie('refreshToken', refreshToken, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
domain: this.config.getOrThrow('COOKIES_DOMAIN'),
|
||||
sameSite: 'lax',
|
||||
maxAge: 30 * 24 * 60 * 60 * 1000
|
||||
})
|
||||
|
||||
return { accessToken }
|
||||
}
|
||||
|
||||
@ApiOperation({
|
||||
summary: 'Refresh',
|
||||
description: 'Refresh access token'
|
||||
})
|
||||
@Post('refresh')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
public async refresh(
|
||||
@Req() req: Request,
|
||||
@Res({ passthrough: true }) res: Response
|
||||
) {
|
||||
const refreshToken = req.cookies?.refreshToken as string
|
||||
|
||||
const { accessToken, refreshToken: newRefreshToken } = await lastValueFrom(
|
||||
this.client.refresh({ refreshToken })
|
||||
)
|
||||
|
||||
res.cookie('refreshToken', newRefreshToken, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
domain: this.config.getOrThrow('COOKIES_DOMAIN'),
|
||||
sameSite: 'lax',
|
||||
maxAge: 30 * 24 * 60 * 60 * 1000
|
||||
})
|
||||
|
||||
return { accessToken }
|
||||
}
|
||||
|
||||
@ApiOperation({
|
||||
summary: 'Logout',
|
||||
description: 'Logout user'
|
||||
})
|
||||
@Post('logout')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
public logout(@Res({ passthrough: true }) res: Response) {
|
||||
res.clearCookie('refreshToken')
|
||||
return { ok: true }
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { Inject, Injectable, OnModuleInit } from '@nestjs/common'
|
||||
import type { ClientGrpc } from '@nestjs/microservices'
|
||||
import {
|
||||
AuthServiceClient,
|
||||
RefreshRequest,
|
||||
SendOtpRequest,
|
||||
VerifyOtpRequest
|
||||
} from '@teacinema/contracts/gen/auth'
|
||||
@ -23,4 +24,8 @@ export class AuthClientGrpc implements OnModuleInit {
|
||||
public verifyOtp(request: VerifyOtpRequest) {
|
||||
return this.authService.verifyOtp(request)
|
||||
}
|
||||
|
||||
public refresh(request: RefreshRequest) {
|
||||
return this.authService.refresh(request)
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import { IdentifierValidator } from '../../../../shared/validators'
|
||||
export class SendOtpRequestDto {
|
||||
@ApiProperty({
|
||||
description: 'User phone or email',
|
||||
example: '+791234567890'
|
||||
example: '+79123456789'
|
||||
})
|
||||
@Validate(IdentifierValidator)
|
||||
@IsString()
|
||||
|
||||
@ -13,7 +13,7 @@ import { IdentifierValidator } from '../../../../shared/validators'
|
||||
export class VerifyOtpRequestDto {
|
||||
@ApiProperty({
|
||||
description: 'User phone or email',
|
||||
example: '+791234567890'
|
||||
example: '+79123456789'
|
||||
})
|
||||
@Validate(IdentifierValidator)
|
||||
@IsString()
|
||||
|
||||
26
yarn.lock
26
yarn.lock
@ -1198,9 +1198,9 @@
|
||||
integrity sha512-L006mySvhRpUlRHf3ONbXA0RG42gbQ9QAnmQuZx4zejHEsWB9702xe18MSYcBilv+lmYkQpiX/g3p8P7suLfqQ==
|
||||
|
||||
"@teacinema/contracts@^1.0.0":
|
||||
version "1.0.4"
|
||||
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.4/contracts-1.0.4.tgz#178dc6392aae52c4dc2b60bb1470a0a2885a8715"
|
||||
integrity sha512-3jHP4NAoH9munaN2Iegvg0X6KN/SR1rwZU7KpbuBtlcTJqsLljTaHwG+XKjEL84Y9b+sF73jGGbg/w2Y8IBQmw==
|
||||
version "1.0.5"
|
||||
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.5/contracts-1.0.5.tgz#f6db65f58ba3621e81e886f54d6ec9e674c4785b"
|
||||
integrity sha512-paFa/zVWKzDNuH04EyGPlG981YEX7Xt42gRwpfZwACGa5CCM5lehT7xKU4h9p/l9IebrOtTPDwJdQn/D41o3Gw==
|
||||
dependencies:
|
||||
"@nestjs/microservices" "^11.1.12"
|
||||
protoc "33.4.0"
|
||||
@ -1314,6 +1314,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/cookie-parser@^1.4.10":
|
||||
version "1.4.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookie-parser/-/cookie-parser-1.4.10.tgz#a045272a383a30597a01955d4f9c790018f214e4"
|
||||
integrity sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==
|
||||
|
||||
"@types/cookiejar@^2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78"
|
||||
@ -2375,12 +2380,25 @@ convert-source-map@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
||||
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
||||
|
||||
cookie-parser@^1.4.7:
|
||||
version "1.4.7"
|
||||
resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.7.tgz#e2125635dfd766888ffe90d60c286404fa0e7b26"
|
||||
integrity sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==
|
||||
dependencies:
|
||||
cookie "0.7.2"
|
||||
cookie-signature "1.0.6"
|
||||
|
||||
cookie-signature@1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
|
||||
|
||||
cookie-signature@^1.2.1, cookie-signature@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793"
|
||||
integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==
|
||||
|
||||
cookie@^0.7.1:
|
||||
cookie@0.7.2, cookie@^0.7.1:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
|
||||
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user