Skip to content

Commit

Permalink
Fix: JWT Payload validation for 2FA Strategy (#235)
Browse files Browse the repository at this point in the history
* fix: corrected jwt validation

* style: lint fixes
  • Loading branch information
hirenf14 authored Sep 12, 2024
1 parent 142a1d3 commit 451e3a4
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 28 deletions.
6 changes: 5 additions & 1 deletion apps/api/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ describe('AuthService', () => {

it('should verify the JWT payload', async () => {
const payload: JwtPayload = {
sub: '[email protected]',
sub: '[email protected]',
email: '[email protected]',
isTwoFactorAuthenticationEnabled: false,
iat: 0,
exp: 0
}
Expand All @@ -176,6 +178,8 @@ describe('AuthService', () => {
it("should throw on verify when JWT's subject not exist", async () => {
const payload: JwtPayload = {
sub: '[email protected]',
email: '[email protected]',
isTwoFactorAuthenticationEnabled: false,
iat: 0,
exp: 0
}
Expand Down
27 changes: 20 additions & 7 deletions apps/api/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,32 @@ export class AuthService {
return { ...user, refresh_token, access_token }
}

async verifyPayload(payload: JwtPayload): Promise<UserEntity> {
let user: UserEntity
async verifyPayload(
payload: JwtPayload
): Promise<UserEntity & { isTwoFactorAuthenticated?: boolean }> {
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<T>(payload: T): SignTokenInterface {
Expand Down
23 changes: 5 additions & 18 deletions apps/api/src/auth/strategies/jwt-2fa.strategy.ts
Original file line number Diff line number Diff line change
@@ -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)
}
}
4 changes: 2 additions & 2 deletions libs/interfaces/src/auth/jwtPayload.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface JwtPayload {
export interface JwtPayload extends LoginWith2FAPayload {
sub: string
iat: number
exp: number
Expand All @@ -10,6 +10,6 @@ export interface LoginWithEmailPayload {

export interface LoginWith2FAPayload {
email: string
isTwoFactorAuthenticated: boolean
isTwoFactorAuthenticated?: boolean
isTwoFactorAuthenticationEnabled: boolean
}

0 comments on commit 451e3a4

Please sign in to comment.