Skip to content

Commit e34e826

Browse files
karuneshsfKarunesh Mani Tripathiyeshamavani
authored
fix(authentication-service): terminate JWT token (#2212)
* fix(authentication-service): terminate JWT token JWT not terminated after logout lead to sensitive data exposure | terminate JWT token after logout GH-2167 * fix(authentication-service): terminate JWT token reverted unnecessary updated files to previous versions GH-2167 * fix(authentication-service): fix typo in README.md fix for typo in README.md GH-2167 --------- Co-authored-by: Karunesh Mani Tripathi <[email protected]> Co-authored-by: yeshamavani <[email protected]>
1 parent b54465a commit e34e826

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

services/authentication-service/src/modules/auth/controllers/logout.controller.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
import {encode} from 'base-64';
2929
import crypto from 'crypto';
3030
import {HttpsProxyAgent} from 'https-proxy-agent';
31+
import jwt from 'jsonwebtoken';
3132
import {
3233
authenticate,
3334
AuthenticationBindings,
@@ -56,6 +57,7 @@ import {
5657
UserTenantRepository,
5758
} from '../../../repositories';
5859
import {ActorId, IUserActivity} from '../../../types';
60+
import {TokenPayload} from '../interfaces';
5961

6062
const proxyUrl = process.env.HTTPS_PROXY ?? process.env.HTTP_PROXY;
6163

@@ -70,6 +72,7 @@ const size = 16;
7072
const SUCCESS_RESPONSE = 'Success Response';
7173
const AUTHENTICATE_USER =
7274
'This is the access token which is required to authenticate user.';
75+
7376
export class LogoutController {
7477
constructor(
7578
@inject(RestBindings.Http.REQUEST) private readonly req: Request,
@@ -136,15 +139,21 @@ export class LogoutController {
136139
AuthenticateErrorKeys.TokenMissing,
137140
);
138141
}
139-
140142
const refreshTokenModel = await this.refreshTokenRepo.get(req.refreshToken);
141143
if (!refreshTokenModel) {
142144
throw new HttpErrors.Unauthorized(AuthErrorKeys.TokenExpired);
143145
}
144146
if (refreshTokenModel.accessToken !== token) {
145147
throw new HttpErrors.Unauthorized(AuthErrorKeys.TokenInvalid);
146148
}
147-
await this.revokedTokens.set(token, {token});
149+
const expiry = this.decodeAndGetExpiry(token);
150+
await this.revokedTokens.set(
151+
token,
152+
{token},
153+
{
154+
ttl: expiry,
155+
},
156+
);
148157
await this.refreshTokenRepo.delete(req.refreshToken);
149158
if (refreshTokenModel.pubnubToken) {
150159
await this.refreshTokenRepo.delete(refreshTokenModel.pubnubToken);
@@ -517,4 +526,27 @@ export class LogoutController {
517526
});
518527
}
519528
}
529+
530+
/**
531+
* The function decodes a JWT token and returns the expiration time in milliseconds.
532+
* @param {string} token - The `token` parameter is a string that represents a JSON Web Token (JWT).
533+
* @returns the expiry time of the token in milliseconds.
534+
*/
535+
/**
536+
* Decodes the given token and retrieves the expiry timestamp.
537+
*
538+
* @param token - The token to decode.
539+
* @returns The expiry timestamp in milliseconds.
540+
*/
541+
decodeAndGetExpiry(token: string): number | null {
542+
const tokenData = jwt.decode(token) as TokenPayload | null; // handle null result from decode
543+
const ms = 1000;
544+
545+
if (tokenData?.exp) {
546+
return tokenData.exp * ms;
547+
}
548+
549+
// If tokenData or exp is missing, return null to indicate no expiry
550+
return null;
551+
}
520552
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './token.interface';
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export interface BaseTokenPayload {
2+
exp?: number; // Optional because the token may not have an expiration field
3+
iat?: number;
4+
}
5+
6+
/**
7+
* @interface TokenPayload
8+
* @extends BaseTokenPayload
9+
*
10+
* Represents the payload of a token used for authentication.
11+
*
12+
* @property {string} userId - The unique identifier of the user.
13+
* @property {string} email - The email address of the user.
14+
* @property {string[]} roles - An array of roles assigned to the user.
15+
*/
16+
export interface TokenPayload extends BaseTokenPayload {
17+
userId: string;
18+
email: string;
19+
roles: string[];
20+
}

0 commit comments

Comments
 (0)