96 lines
3.3 KiB
TypeScript
96 lines
3.3 KiB
TypeScript
import { Controller, Post, Get, Patch, Body, Req, Res, HttpCode, HttpStatus } from '@nestjs/common';
|
|
import {
|
|
ApiTags,
|
|
ApiOperation,
|
|
ApiBearerAuth,
|
|
ApiCreatedResponse,
|
|
ApiOkResponse,
|
|
} from '@nestjs/swagger';
|
|
import { Request, Response } from 'express';
|
|
import { AuthService } from './auth.service';
|
|
import { RegisterDto } from './dto/register.dto';
|
|
import { LoginDto } from './dto/login.dto';
|
|
import { UpdateProfileDto } from './dto/update-profile.dto';
|
|
import {
|
|
AuthLogoutResponseDto,
|
|
AuthProfileResponseDto,
|
|
AuthTokenResponseDto,
|
|
} from './dto/auth-response.dto';
|
|
import { CurrentUser } from './decorators/current-user.decorator';
|
|
import { Public } from './decorators/public.decorator';
|
|
import { JwtPayload } from './interfaces/jwt-payload.interface';
|
|
|
|
const REFRESH_COOKIE = 'refresh_token';
|
|
const COOKIE_OPTIONS = {
|
|
httpOnly: true,
|
|
sameSite: 'lax' as const,
|
|
secure: process.env.NODE_ENV === 'production',
|
|
path: '/api/v1/auth',
|
|
maxAge: 7 * 24 * 60 * 60 * 1000,
|
|
};
|
|
|
|
@ApiTags('Auth')
|
|
@Controller('auth')
|
|
export class AuthController {
|
|
constructor(private readonly authService: AuthService) {}
|
|
|
|
@Public()
|
|
@Post('register')
|
|
@ApiOperation({ summary: 'Register new user' })
|
|
@ApiCreatedResponse({ type: AuthTokenResponseDto })
|
|
async register(@Body() dto: RegisterDto, @Res({ passthrough: true }) res: Response) {
|
|
const result = await this.authService.register(dto);
|
|
res.cookie(REFRESH_COOKIE, result.refreshToken, COOKIE_OPTIONS);
|
|
return { user: result.user, accessToken: result.accessToken };
|
|
}
|
|
|
|
@Public()
|
|
@Post('login')
|
|
@ApiOperation({ summary: 'Login with email and password' })
|
|
@ApiCreatedResponse({ type: AuthTokenResponseDto })
|
|
async login(@Body() dto: LoginDto, @Res({ passthrough: true }) res: Response) {
|
|
const result = await this.authService.login(dto);
|
|
res.cookie(REFRESH_COOKIE, result.refreshToken, COOKIE_OPTIONS);
|
|
return { user: result.user, accessToken: result.accessToken };
|
|
}
|
|
|
|
@Public()
|
|
@Post('refresh')
|
|
@HttpCode(HttpStatus.OK)
|
|
@ApiOperation({ summary: 'Refresh access token' })
|
|
@ApiOkResponse({ type: AuthTokenResponseDto })
|
|
async refresh(@Req() req: Request, @Res({ passthrough: true }) res: Response) {
|
|
const token = req.cookies?.[REFRESH_COOKIE];
|
|
const result = await this.authService.refresh(token);
|
|
res.cookie(REFRESH_COOKIE, result.refreshToken, COOKIE_OPTIONS);
|
|
return { user: result.user, accessToken: result.accessToken };
|
|
}
|
|
|
|
@Post('logout')
|
|
@HttpCode(HttpStatus.OK)
|
|
@ApiBearerAuth()
|
|
@ApiOperation({ summary: 'Logout user' })
|
|
@ApiOkResponse({ type: AuthLogoutResponseDto })
|
|
async logout(@CurrentUser() user: JwtPayload, @Res({ passthrough: true }) res: Response) {
|
|
await this.authService.logout(user.sub);
|
|
res.clearCookie(REFRESH_COOKIE, { path: '/api/v1/auth' });
|
|
return { message: 'Logged out successfully' };
|
|
}
|
|
|
|
@Get('me')
|
|
@ApiBearerAuth()
|
|
@ApiOperation({ summary: 'Get current user profile' })
|
|
@ApiOkResponse({ type: AuthProfileResponseDto })
|
|
async getProfile(@CurrentUser() user: JwtPayload) {
|
|
return this.authService.getProfile(user.sub);
|
|
}
|
|
|
|
@Patch('me')
|
|
@ApiBearerAuth()
|
|
@ApiOperation({ summary: 'Update current user profile' })
|
|
@ApiOkResponse({ type: AuthProfileResponseDto })
|
|
async updateProfile(@CurrentUser() user: JwtPayload, @Body() dto: UpdateProfileDto) {
|
|
return this.authService.updateProfile(user.sub, dto);
|
|
}
|
|
}
|