Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/modules/auth/controller/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class AuthController {
@UseGuards(BearerAuthGuard)
@PostLogoutSwagger()
async logout(@Res({ passthrough: true }) res: FastifyReply, @Req() req: FastifyRequest) {
const session = req.cookies['refresh'];
const session = req.cookies?.['refresh'];
const response = await this.facade.signOut(session);

res.clearCookie('refresh', { path: '/' });
Expand All @@ -83,7 +83,7 @@ export class AuthController {
@HttpCode(200)
async refresh(@Res({ passthrough: true }) res: FastifyReply, @Req() req: FastifyRequest) {
const meta = getDeviceMeta(req);
const session = req.cookies['refresh'];
const session = req.cookies?.['refresh'];
const { tokens, ...response } = await this.facade.refresh(session, meta);

res.setCookie('refresh', tokens.refresh, {
Expand Down
5 changes: 3 additions & 2 deletions src/modules/auth/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ export class AuthService {
};

public signIn = async (dto: SignInDto, meta: DeviceMetadata) => {
const { user, security } = await this.findUserCommand.execute({ email: dto.email });
const entities = await this.findUserCommand.execute({ email: dto.email });

if (!user || !security) {
if (!entities?.user || !entities?.security) {
throw new BaseException(
{
code: 'INVALID_CREDENTIALS',
Expand All @@ -163,6 +163,7 @@ export class AuthService {
);
}

const { security, user } = entities;
const isPasswordValid = await argon.verify(security.passwordHash, dto.password);

if (!isPasswordValid) {
Expand Down
15 changes: 8 additions & 7 deletions src/modules/auth/services/token.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import type { JwtPayload } from '@shared/types';
import type { User } from '@core/modules/user';

@Injectable()
export class TokenService {
Expand All @@ -10,16 +11,16 @@ export class TokenService {
private readonly cfg: ConfigService,
) {}

async generateTokens(user: any, sessionId: string) {
async generateTokens(user: User, sessionId: string) {
const domain = this.cfg.get('DOMAIN');
const audConstraint = this.cfg.getOrThrow('JWT_AUDIENCE');

const payload = {
jti: sessionId,
sub: user.id,
email: user.email,
iss: btoa(domain),
aud: btoa(this.cfg.getOrThrow('JWT_AUDIENCE')),
role: user.role,
aud: btoa(audConstraint),
};

const [access, refresh] = await Promise.all([
Expand All @@ -38,10 +39,10 @@ export class TokenService {

async validateToken(token: string, type: 'access' | 'refresh'): Promise<JwtPayload> {
try {
const secret =
type === 'access'
? this.cfg.get('JWT_ACCESS_SECRET')
: this.cfg.get('JWT_REFRESH_SECRET');
const accessSecret = this.cfg.get('JWT_ACCESS_SECRET');
const refreshSecret = this.cfg.get('JWT_REFRESH_SECRET');

const secret = type === 'access' ? accessSecret : refreshSecret;

return this.jwtService.verifyAsync(token, { secret });
} catch (e) {
Expand Down
11 changes: 7 additions & 4 deletions src/modules/auth/strategies/bearer.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import { Strategy, ExtractJwt } from 'passport-jwt';

@Injectable()
export class BearerStrategy extends PassportStrategy(Strategy, 'bearer') {
constructor(configService: ConfigService) {
constructor(cfg: ConfigService) {
const audConstraint = cfg.getOrThrow('JWT_AUDIENCE');
const audience = btoa(audConstraint);

super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: configService.get<string>('JWT_ACCESS_SECRET'),
issuer: configService.get<string>('JWT_ISSUER'),
audience: configService.get<string>('JWT_AUDIENCE'),
secretOrKey: cfg.get<string>('JWT_ACCESS_SECRET'),
issuer: cfg.get<string>('JWT_ISSUER'),
audience,
});
}

Expand Down
4 changes: 3 additions & 1 deletion src/modules/auth/strategies/cookie.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export class CookieStrategy extends PassportStrategy(Strategy, 'cookie') {
super({
jwtFromRequest: ExtractJwt.fromExtractors([
(request: FastifyRequest) => {
return request?.cookies?.['refresh'];
const token = request?.cookies?.['refresh'];
return token;
},
]),
secretOrKey: configService.get<string>('JWT_REFRESH_SECRET'),
Expand All @@ -21,6 +22,7 @@ export class CookieStrategy extends PassportStrategy(Strategy, 'cookie') {
}

validate(_req: FastifyRequest, payload: JwtPayload) {
console.log(_req, payload);
if (!payload || !payload.jti) {
throw new BaseException(
{
Expand Down
1 change: 0 additions & 1 deletion src/modules/user/entities/user.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export const users = baseSchema.table('users', {
firstName: varchar('first_name', { length: 50 }).notNull(),
lastName: varchar('last_name', { length: 50 }).notNull(),
middleName: varchar('middle_name', { length: 50 }),

email: varchar('email', { length: 255 }).notNull().unique(),
bio: text('bio'),
avatarUrl: varchar('avatar_url', { length: 512 }),
Expand Down
1 change: 1 addition & 0 deletions src/modules/user/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { UserModule } from './user.module';
export { UserRepository } from './repository/user.repository';
export { CreateUserCommand, FindOneUserCommand, UpdatePassUserCommand } from './commands';
export { User } from './entities/user.domain';
26 changes: 24 additions & 2 deletions src/shared/guards/cookie.guard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
import { Injectable } from '@nestjs/common';
import { HttpStatus, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { BaseException } from '@shared/error';
import type { JwtPayload } from '@shared/types';

@Injectable()
export class CookieAuthGuard extends AuthGuard('cookie') {}
export class CookieAuthGuard extends AuthGuard('cookie') {
handleRequest<TUser = JwtPayload>(err: unknown, user: TUser, info: any): TUser {
if (err || !user) {
throw new BaseException(
{
code: 'INVALID_REFRESH_TOKEN',
message: 'Refresh токен невалиден или отсутствует',
details: [
{
target: 'auth',
reason: info?.message || 'Token verification failed',
},
],
},
HttpStatus.UNAUTHORIZED,
);
}

return user;
}
}
Loading