Skip to content

Commit 41a3b2d

Browse files
Piyush Singh GaurPiyush Singh Gaur
authored andcommitted
fix(authentication-service): make authorization code one-time-use and centralize TTL constant
make authorization code one-time-use and centralize TTL constant GH-2495
1 parent 239cde5 commit 41a3b2d

File tree

1 file changed

+20
-8
lines changed

1 file changed

+20
-8
lines changed

services/authentication-service/src/services/idp-login.service.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ export class IdpLoginService {
8888
@inject(AuthServiceBindings.MarkUserActivity, {optional: true})
8989
private readonly userActivity?: IUserActivity,
9090
) {}
91+
92+
private readonly msInSecond = 1000;
9193

9294
/**
9395
* Retrieves OpenID Connect configuration settings.
@@ -165,13 +167,27 @@ export class IdpLoginService {
165167
}
166168
try {
167169
const resultCode = await this.codeReader(request.code);
170+
171+
// Check if the authorization code has already been used (one-time-use enforcement)
172+
const isCodeRevoked = await this.revokedTokensRepo.get(resultCode);
173+
if (isCodeRevoked) {
174+
throw new HttpErrors.Unauthorized(AuthErrorKeys.CodeExpired);
175+
}
176+
168177
const payload = (await this.jwtVerifier(resultCode, {
169178
audience: request.clientId,
170179
})) as ClientAuthCode<User, typeof User.prototype.id>;
171180
if (payload.mfa) {
172181
throw new HttpErrors.Unauthorized(AuthErrorKeys.UserVerificationFailed);
173182
}
174183

184+
// Revoke the auth code immediately after verification to prevent reuse
185+
await this.revokedTokensRepo.set(
186+
resultCode,
187+
{token: resultCode},
188+
{ttl: authClient.authCodeExpiration * this.msInSecond},
189+
);
190+
175191
if (
176192
payload.user?.id &&
177193
!(await this.userRepo.firstTimeUser(payload.user.id))
@@ -211,7 +227,6 @@ export class IdpLoginService {
211227
accessToken: string,
212228
data: AnyObject,
213229
): Promise<void> {
214-
const ms = 1000;
215230
await this.refreshTokenRepo.set(
216231
refreshToken,
217232
{
@@ -223,7 +238,7 @@ export class IdpLoginService {
223238
externalRefreshToken: (user as AuthUser).externalRefreshToken,
224239
tenantId: data.tenantId,
225240
},
226-
{ttl: authClient.refreshTokenExpiration * ms},
241+
{ttl: authClient.refreshTokenExpiration * this.msInSecond},
227242
);
228243
}
229244

@@ -292,7 +307,6 @@ export class IdpLoginService {
292307
tenantId?: string,
293308
): Promise<TokenResponse> {
294309
const size = 32;
295-
const ms = 1000;
296310
try {
297311
const user = await this.getUser(payload);
298312
const data: AnyObject = await this.getJwtPayload(
@@ -323,7 +337,7 @@ export class IdpLoginService {
323337
publicKey: key.publicKey,
324338
},
325339
{
326-
ttl: authClient.accessTokenExpiration * ms,
340+
ttl: authClient.accessTokenExpiration * this.msInSecond,
327341
},
328342
);
329343
}
@@ -602,7 +616,6 @@ export class IdpLoginService {
602616
this.currentUser?.authClientId,
603617
);
604618

605-
const ms = 1000;
606619
// Save the public key to the cache for retrieval on facade
607620
await this.publicKeyRepo.set(
608621
key.kid,
@@ -611,7 +624,7 @@ export class IdpLoginService {
611624
publicKey,
612625
},
613626
{
614-
ttl: authClient.accessTokenExpiration * ms,
627+
ttl: authClient.accessTokenExpiration * this.msInSecond,
615628
},
616629
);
617630
}
@@ -637,10 +650,9 @@ export class IdpLoginService {
637650
*/
638651
private decodeAndGetExpiry(token: string): number | null {
639652
const tokenData = jwt.decode(token) as TokenPayload | null; // handle null result from decode
640-
const ms = 1000;
641653

642654
if (tokenData?.exp) {
643-
return tokenData.exp * ms;
655+
return tokenData.exp * this.msInSecond;
644656
}
645657

646658
// If tokenData or exp is missing, return null to indicate no expiry

0 commit comments

Comments
 (0)