mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-17 08:31:47 +03:00
feat: add cooldown to refresh token security (#1736)
This commit is contained in:
parent
96865b0fec
commit
a4cde44b13
@ -114,6 +114,7 @@ export class TokenService {
|
||||
|
||||
async verifyRefreshToken(refreshToken: string) {
|
||||
const secret = this.environmentService.getRefreshTokenSecret();
|
||||
const coolDown = this.environmentService.getRefreshTokenCoolDown();
|
||||
const jwtPayload = await this.verifyJwt(refreshToken, secret);
|
||||
|
||||
assert(
|
||||
@ -139,7 +140,11 @@ export class TokenService {
|
||||
|
||||
assert(user, 'User not found', NotFoundException);
|
||||
|
||||
if (token.isRevoked) {
|
||||
// Check if revokedAt is less than coolDown
|
||||
if (
|
||||
token.revokedAt &&
|
||||
token.revokedAt.getTime() <= Date.now() - ms(coolDown)
|
||||
) {
|
||||
// Revoke all user refresh tokens
|
||||
await this.prismaService.client.refreshToken.updateMany({
|
||||
where: {
|
||||
@ -148,16 +153,14 @@ export class TokenService {
|
||||
},
|
||||
},
|
||||
data: {
|
||||
isRevoked: true,
|
||||
revokedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
assert(
|
||||
!token.isRevoked,
|
||||
'Suspicious activity detected, this refresh token has been revoked. All tokens has been revoked.',
|
||||
ForbiddenException,
|
||||
);
|
||||
throw new ForbiddenException(
|
||||
'Suspicious activity detected, this refresh token has been revoked. All tokens has been revoked.',
|
||||
);
|
||||
}
|
||||
|
||||
return { user, token };
|
||||
}
|
||||
@ -177,7 +180,7 @@ export class TokenService {
|
||||
id,
|
||||
},
|
||||
data: {
|
||||
isRevoked: true,
|
||||
revokedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
-- Step 1: Add the new column
|
||||
ALTER TABLE "refresh_tokens" ADD COLUMN "revokedAt" TIMESTAMP(3);
|
||||
|
||||
-- Step 2: Update the new column based on the isRevoked column value
|
||||
UPDATE "refresh_tokens" SET "revokedAt" = NOW() - INTERVAL '1 day' WHERE "isRevoked" = TRUE;
|
||||
|
||||
-- Step 3: Drop the isRevoked column
|
||||
ALTER TABLE "refresh_tokens" DROP COLUMN "isRevoked";
|
@ -331,10 +331,7 @@ model Person {
|
||||
model RefreshToken {
|
||||
/// @Validator.IsString()
|
||||
/// @Validator.IsOptional()
|
||||
id String @id @default(uuid())
|
||||
/// @Validator.IsBoolean()
|
||||
/// @Validator.IsOptional()
|
||||
isRevoked Boolean @default(false)
|
||||
id String @id @default(uuid())
|
||||
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
@ -344,6 +341,8 @@ model RefreshToken {
|
||||
expiresAt DateTime
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
deletedAt DateTime?
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
revokedAt DateTime?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
@ -61,6 +61,10 @@ export class EnvironmentService {
|
||||
return this.configService.get<string>('REFRESH_TOKEN_EXPIRES_IN') ?? '90d';
|
||||
}
|
||||
|
||||
getRefreshTokenCoolDown(): string {
|
||||
return this.configService.get<string>('REFRESH_TOKEN_COOL_DOWN') ?? '1m';
|
||||
}
|
||||
|
||||
getLoginTokenSecret(): string {
|
||||
return this.configService.get<string>('LOGIN_TOKEN_SECRET')!;
|
||||
}
|
||||
|
@ -76,6 +76,9 @@ export class EnvironmentVariables {
|
||||
@IsDuration()
|
||||
@IsOptional()
|
||||
REFRESH_TOKEN_EXPIRES_IN: string;
|
||||
@IsDuration()
|
||||
@IsOptional()
|
||||
REFRESH_TOKEN_COOL_DOWN: string;
|
||||
|
||||
@IsString()
|
||||
LOGIN_TOKEN_SECRET: string;
|
||||
|
Loading…
Reference in New Issue
Block a user