From 451e3a465a738589d8a4cb50b521d0956068aacc Mon Sep 17 00:00:00 2001 From: Hiren F <146440442+hirenf14@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:00:38 +0530 Subject: [PATCH] Fix: JWT Payload validation for 2FA Strategy (#235) * fix: corrected jwt validation * style: lint fixes --- apps/api/src/auth/auth.service.spec.ts | 6 ++++- apps/api/src/auth/auth.service.ts | 27 ++++++++++++++----- .../src/auth/strategies/jwt-2fa.strategy.ts | 23 ++++------------ .../src/auth/jwtPayload.interface.ts | 4 +-- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/apps/api/src/auth/auth.service.spec.ts b/apps/api/src/auth/auth.service.spec.ts index 5b2e68d..3538003 100644 --- a/apps/api/src/auth/auth.service.spec.ts +++ b/apps/api/src/auth/auth.service.spec.ts @@ -159,7 +159,9 @@ describe('AuthService', () => { it('should verify the JWT payload', async () => { const payload: JwtPayload = { - sub: 'john@doe.me', + sub: 'notregistered@example.com', + email: 'notregistered@example.com', + isTwoFactorAuthenticationEnabled: false, iat: 0, exp: 0 } @@ -176,6 +178,8 @@ describe('AuthService', () => { it("should throw on verify when JWT's subject not exist", async () => { const payload: JwtPayload = { sub: 'notregistered@example.com', + email: 'notregistered@example.com', + isTwoFactorAuthenticationEnabled: false, iat: 0, exp: 0 } diff --git a/apps/api/src/auth/auth.service.ts b/apps/api/src/auth/auth.service.ts index 1840926..f1f056b 100644 --- a/apps/api/src/auth/auth.service.ts +++ b/apps/api/src/auth/auth.service.ts @@ -101,19 +101,32 @@ export class AuthService { return { ...user, refresh_token, access_token } } - async verifyPayload(payload: JwtPayload): Promise { - let user: UserEntity + async verifyPayload( + payload: JwtPayload + ): Promise { + let user: UserEntity & { isTwoFactorAuthenticated?: boolean } try { - user = await this.userService.findOne({ where: { email: payload.sub } }) + user = await this.userService.findOne({ + where: { email: payload.email } + }) + + if (!user.isTwoFAEnabled) { + return user + } + + if (payload.isTwoFactorAuthenticated) { + user.isTwoFactorAuthenticated = payload.isTwoFactorAuthenticated + } + + delete user.password + + return user } catch (error) { throw new UnauthorizedException( - `There isn't any user with email: ${payload.sub}` + `There isn't any user with email: ${payload.email}` ) } - delete user.password - - return user } signToken(payload: T): SignTokenInterface { diff --git a/apps/api/src/auth/strategies/jwt-2fa.strategy.ts b/apps/api/src/auth/strategies/jwt-2fa.strategy.ts index 6f45561..7217521 100644 --- a/apps/api/src/auth/strategies/jwt-2fa.strategy.ts +++ b/apps/api/src/auth/strategies/jwt-2fa.strategy.ts @@ -1,32 +1,19 @@ import { ExtractJwt, Strategy } from 'passport-jwt' import { PassportStrategy } from '@nestjs/passport' import { Injectable } from '@nestjs/common' -import { UserService } from '../../user/user.service' -import { LoginWith2FAPayload } from '@isomera/interfaces' +import { JwtPayload } from '@isomera/interfaces' +import { AuthService } from '../auth.service' @Injectable() export class Jwt2faStrategy extends PassportStrategy(Strategy, 'jwt-2fa') { - constructor(private readonly userService: UserService) { + constructor(private readonly authService: AuthService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: process.env.APP_SECRET }) } - async validate(payload: LoginWith2FAPayload) { - const user = await this.userService.findOne({ - where: { email: payload.email } - }) - - if (!user.isTwoFAEnabled) { - return user - } - - if (payload.isTwoFactorAuthenticated) { - return { - ...user, - isTwoFactorAuthenticated: payload.isTwoFactorAuthenticated - } - } + async validate(payload: JwtPayload) { + return this.authService.verifyPayload(payload) } } diff --git a/libs/interfaces/src/auth/jwtPayload.interface.ts b/libs/interfaces/src/auth/jwtPayload.interface.ts index 117f8b1..2ac2c3c 100644 --- a/libs/interfaces/src/auth/jwtPayload.interface.ts +++ b/libs/interfaces/src/auth/jwtPayload.interface.ts @@ -1,4 +1,4 @@ -export interface JwtPayload { +export interface JwtPayload extends LoginWith2FAPayload { sub: string iat: number exp: number @@ -10,6 +10,6 @@ export interface LoginWithEmailPayload { export interface LoginWith2FAPayload { email: string - isTwoFactorAuthenticated: boolean + isTwoFactorAuthenticated?: boolean isTwoFactorAuthenticationEnabled: boolean }