diff --git a/apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts b/apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts index 6660228cf5..e8b30a13d3 100644 --- a/apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts +++ b/apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts @@ -177,7 +177,7 @@ export class OAuthClientUsersController { const { id } = await this.validateManagedUserOwnership(oAuthClientId, userId); const { accessToken, refreshToken, accessTokenExpiresAt, refreshTokenExpiresAt } = - await this.tokensRepository.createOAuthTokens(oAuthClientId, id, true); + await this.tokensRepository.forceRefreshOAuthTokens(oAuthClientId, id); return { status: SUCCESS_STATUS, diff --git a/apps/api/v2/src/modules/tokens/tokens.repository.ts b/apps/api/v2/src/modules/tokens/tokens.repository.ts index 074d1b0bac..2442c117e7 100644 --- a/apps/api/v2/src/modules/tokens/tokens.repository.ts +++ b/apps/api/v2/src/modules/tokens/tokens.repository.ts @@ -5,6 +5,7 @@ import { Injectable } from "@nestjs/common"; import { Logger } from "@nestjs/common"; import { PlatformAuthorizationToken } from "@prisma/client"; import { DateTime } from "luxon"; +import { v4 as uuidv4 } from "uuid"; @Injectable() export class TokensRepository { @@ -50,31 +51,18 @@ export class TokensRepository { }); } - async createOAuthTokens(clientId: string, ownerId: number, deleteOld?: boolean) { - if (deleteOld) { - try { - await this.dbWrite.prisma.$transaction([ - this.dbWrite.prisma.accessToken.deleteMany({ - where: { client: { id: clientId }, userId: ownerId }, - }), - this.dbWrite.prisma.refreshToken.deleteMany({ - where: { - client: { id: clientId }, - userId: ownerId, - }, - }), - ]); - } catch (err) { - this.logger.error("createOAuthTokens - Failed to delete old tokens", err); - } - } - + async createOAuthTokens(clientId: string, ownerId: number) { const accessExpiry = DateTime.now().plus({ minute: 60 }).startOf("minute").toJSDate(); const refreshExpiry = DateTime.now().plus({ year: 1 }).startOf("day").toJSDate(); const [accessToken, refreshToken] = await this.dbWrite.prisma.$transaction([ this.dbWrite.prisma.accessToken.create({ data: { - secret: this.jwtService.signAccessToken({ clientId, ownerId, expiresAt: accessExpiry.valueOf() }), + secret: this.jwtService.signAccessToken({ + clientId, + ownerId, + expiresAt: accessExpiry.valueOf(), + jti: uuidv4(), + }), expiresAt: accessExpiry, client: { connect: { id: clientId } }, owner: { connect: { id: ownerId } }, @@ -82,7 +70,12 @@ export class TokensRepository { }), this.dbWrite.prisma.refreshToken.create({ data: { - secret: this.jwtService.signRefreshToken({ clientId, ownerId, expiresAt: refreshExpiry.valueOf() }), + secret: this.jwtService.signRefreshToken({ + clientId, + ownerId, + expiresAt: refreshExpiry.valueOf(), + jti: uuidv4(), + }), expiresAt: refreshExpiry, client: { connect: { id: clientId } }, owner: { connect: { id: ownerId } }, @@ -98,6 +91,57 @@ export class TokensRepository { }; } + async forceRefreshOAuthTokens(clientId: string, ownerId: number) { + const accessExpiry = DateTime.now().plus({ minute: 60 }).startOf("minute").toJSDate(); + const refreshExpiry = DateTime.now().plus({ year: 1 }).startOf("day").toJSDate(); + + const [_deletedAccessToken, _deletedRefreshToken, accessToken, refreshToken] = + await this.dbWrite.prisma.$transaction([ + this.dbWrite.prisma.accessToken.deleteMany({ + where: { client: { id: clientId }, userId: ownerId }, + }), + this.dbWrite.prisma.refreshToken.deleteMany({ + where: { + client: { id: clientId }, + userId: ownerId, + }, + }), + this.dbWrite.prisma.accessToken.create({ + data: { + secret: this.jwtService.signAccessToken({ + clientId, + ownerId, + expiresAt: accessExpiry.valueOf(), + jti: uuidv4(), + }), + expiresAt: accessExpiry, + client: { connect: { id: clientId } }, + owner: { connect: { id: ownerId } }, + }, + }), + this.dbWrite.prisma.refreshToken.create({ + data: { + secret: this.jwtService.signRefreshToken({ + clientId, + ownerId, + expiresAt: refreshExpiry.valueOf(), + jti: uuidv4(), + }), + expiresAt: refreshExpiry, + client: { connect: { id: clientId } }, + owner: { connect: { id: ownerId } }, + }, + }), + ]); + + return { + accessToken: accessToken.secret, + accessTokenExpiresAt: accessToken.expiresAt, + refreshToken: refreshToken.secret, + refreshTokenExpiresAt: refreshToken.expiresAt, + }; + } + async getAccessTokenExpiryDate(accessTokenSecret: string) { const accessToken = await this.dbRead.prisma.accessToken.findFirst({ where: { @@ -140,6 +184,7 @@ export class TokensRepository { ownerId: tokenUserId, expiresAt: accessExpiry.valueOf(), userId: tokenUserId, + jti: uuidv4(), }), expiresAt: accessExpiry, client: { connect: { id: clientId } }, @@ -155,6 +200,7 @@ export class TokensRepository { ownerId: tokenUserId, expiresAt: refreshExpiry.valueOf(), userId: tokenUserId, + jti: uuidv4(), }), expiresAt: refreshExpiry, client: { connect: { id: clientId } },