Skip to content

Commit 820863a

Browse files
committed
fix:add exp logic in jwt strategy
Signed-off-by: shitrerohit <[email protected]>
1 parent ab9fb63 commit 820863a

File tree

4 files changed

+29
-23
lines changed

4 files changed

+29
-23
lines changed

apps/api-gateway/src/authz/jwt.strategy.ts

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import * as dotenv from 'dotenv';
2+
import * as jwt from 'jsonwebtoken';
23

34
import { ExtractJwt, Strategy } from 'passport-jwt';
4-
import { Injectable, Logger, UnauthorizedException, NotFoundException } from '@nestjs/common';
5+
import { Injectable, Logger, NotFoundException, UnauthorizedException } from '@nestjs/common';
56

7+
import { AuthzService } from './authz.service';
8+
import { CommonConstants } from '@credebl/common/common.constant';
9+
import { IOrganization } from '@credebl/common/interfaces/organization.interface';
610
import { JwtPayload } from './jwt-payload.interface';
11+
import { OrganizationService } from '../organization/organization.service';
712
import { PassportStrategy } from '@nestjs/passport';
13+
import { ResponseMessages } from '@credebl/common/response-messages';
814
import { UserService } from '../user/user.service';
9-
import * as jwt from 'jsonwebtoken';
1015
import { passportJwtSecret } from 'jwks-rsa';
11-
import { CommonConstants } from '@credebl/common/common.constant';
12-
import { OrganizationService } from '../organization/organization.service';
13-
import { IOrganization } from '@credebl/common/interfaces/organization.interface';
14-
import { ResponseMessages } from '@credebl/common/response-messages';
1516

1617
dotenv.config();
1718

@@ -21,15 +22,20 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
2122

2223
constructor(
2324
private readonly usersService: UserService,
24-
private readonly organizationService: OrganizationService
25-
) {
26-
25+
private readonly organizationService: OrganizationService,
26+
private readonly authzService: AuthzService
27+
) {
2728
super({
2829
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
29-
secretOrKeyProvider: (request, jwtToken, done) => {
30+
secretOrKeyProvider: async (request, jwtToken, done) => {
31+
// Todo: We need to add this logic in seprate jwt gurd to handle the token expiration functionality.
3032
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3133
const decodedToken: any = jwt.decode(jwtToken);
32-
34+
const currentTime = Math.floor(Date.now() / 1000);
35+
if (decodedToken?.exp < currentTime) {
36+
const sessionIds = { sessions: [decodedToken?.sid] };
37+
await this.authzService.logout(sessionIds);
38+
}
3339
if (!decodedToken) {
3440
throw new UnauthorizedException(ResponseMessages.user.error.invalidAccessToken);
3541
}
@@ -49,26 +55,25 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
4955
});
5056
},
5157
algorithms: ['RS256']
52-
});
58+
});
5359
}
5460

5561
async validate(payload: JwtPayload): Promise<object> {
56-
5762
let userDetails = null;
5863
let userInfo;
5964

6065
if (payload?.email) {
6166
userInfo = await this.usersService.getUserByUserIdInKeycloak(payload?.email);
6267
}
63-
68+
6469
if (payload.hasOwnProperty('client_id')) {
6570
const orgDetails: IOrganization = await this.organizationService.findOrganizationOwner(payload['client_id']);
66-
71+
6772
this.logger.log('Organization details fetched');
6873
if (!orgDetails) {
6974
throw new NotFoundException(ResponseMessages.organisation.error.orgNotFound);
7075
}
71-
76+
7277
// eslint-disable-next-line prefer-destructuring
7378
const userOrgDetails = 0 < orgDetails.userOrgRoles.length && orgDetails.userOrgRoles[0];
7479

@@ -83,11 +88,10 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
8388
});
8489

8590
this.logger.log('User details set');
86-
8791
} else {
8892
userDetails = await this.usersService.findUserinKeycloak(payload.sub);
8993
}
90-
94+
9195
if (!userDetails) {
9296
throw new NotFoundException(ResponseMessages.user.error.notFound);
9397
}

apps/user/interfaces/user.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export interface IUserSignIn {
182182
}
183183

184184
export interface ISession {
185+
id?: string;
185186
sessionToken?: string;
186187
userId?: string;
187188
expires?: number;

apps/user/repositories/user.repository.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,7 @@ export class UserRepository {
681681
const { sessionToken, userId, expires, refreshToken, accountId, sessionType } = tokenDetails;
682682
const sessionResponse = await this.prisma.session.create({
683683
data: {
684+
id: tokenDetails.id,
684685
sessionToken,
685686
expires,
686687
userId,
@@ -959,7 +960,7 @@ export class UserRepository {
959960
}
960961
}
961962

962-
async deleteSessionRecordByRefreshToken(sessionId: string): Promise<session> {
963+
async deleteSession(sessionId: string): Promise<session> {
963964
try {
964965
const userSession = await this.prisma.session.delete({
965966
where: {

apps/user/src/user.service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,7 @@ export class UserService {
449449
try {
450450
this.validateEmail(email.toLowerCase());
451451
const userData = await this.userRepository.checkUserExist(email.toLowerCase());
452-
453452
const userSessionDetails = await this.userRepository.fetchUserSessions(userData?.id);
454-
455453
if (Number(process.env.SESSIONS_LIMIT) <= userSessionDetails?.length) {
456454
throw new BadRequestException(ResponseMessages.user.error.sessionLimitReached);
457455
}
@@ -475,8 +473,10 @@ export class UserService {
475473
} else {
476474
const decryptedPassword = await this.commonService.decryptPassword(password);
477475
const tokenDetails = await this.generateToken(email.toLowerCase(), decryptedPassword, userData);
478-
476+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
477+
const decodedToken: any = jwt.decode(tokenDetails?.access_token);
479478
const sessionData = {
479+
id: decodedToken.sid,
480480
sessionToken: tokenDetails?.access_token,
481481
userId: userData?.id,
482482
expires: tokenDetails?.expires_in,
@@ -553,7 +553,7 @@ export class UserService {
553553
throw new NotFoundException(ResponseMessages.user.error.userSeesionNotFound);
554554
}
555555
// Delete previous session
556-
const deletePreviousSession = await this.userRepository.deleteSessionRecordByRefreshToken(sessionDetails.id);
556+
const deletePreviousSession = await this.userRepository.deleteSession(sessionDetails.id);
557557
if (!deletePreviousSession) {
558558
throw new InternalServerErrorException(ResponseMessages.user.error.errorInDeleteSession);
559559
}

0 commit comments

Comments
 (0)