From 95e1838303cfedf738e8458367533977a3a40589 Mon Sep 17 00:00:00 2001 From: paritosh18 Date: Thu, 19 Feb 2026 12:44:55 +0530 Subject: [PATCH] Add generateAccessFromRefreshToken handler to issue new access tokens --- serverless/functions/user.yml | 15 +++ .../generateRefereshToAccess.ts | 95 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/modules/user/handlers/authentication/generateRefereshToAccess.ts diff --git a/serverless/functions/user.yml b/serverless/functions/user.yml index ac23b62..e9f9986 100644 --- a/serverless/functions/user.yml +++ b/serverless/functions/user.yml @@ -46,6 +46,21 @@ verifyOtpForUser: path: /user/verify-otp method: post +generateAccessFromRefreshToken: + handler: src/modules/user/handlers/authentication/generateRefereshToAccess.handler + memorySize: 384 + package: + patterns: + - 'src/modules/user/**' + - ${file(./serverless/patterns/base.yml):pattern1} + - ${file(./serverless/patterns/base.yml):pattern2} + - ${file(./serverless/patterns/base.yml):pattern3} + - ${file(./serverless/patterns/base.yml):pattern4} + events: + - httpApi: + path: /user/generate-access-from-refresh + method: post + setPasscodeForMobile: handler: src/modules/user/handlers/authentication/setPasscodeForMobile.handler diff --git a/src/modules/user/handlers/authentication/generateRefereshToAccess.ts b/src/modules/user/handlers/authentication/generateRefereshToAccess.ts new file mode 100644 index 0000000..5bce2e0 --- /dev/null +++ b/src/modules/user/handlers/authentication/generateRefereshToAccess.ts @@ -0,0 +1,95 @@ +import { + APIGatewayProxyEvent, + APIGatewayProxyResult, + Context, +} from 'aws-lambda'; +import { JwtPayload } from 'jsonwebtoken'; +import { prismaClient } from '../../../../common/database/prisma.lambda.service'; +import { safeHandler } from '../../../../common/utils/handlers/safeHandler'; +import ApiError from '../../../../common/utils/helper/ApiError'; +import { TokenService } from '../../../host/services/token.service'; + +const tokenService = new TokenService(prismaClient); + +export const handler = safeHandler( + async ( + event: APIGatewayProxyEvent, + context?: Context, + ): Promise => { + // Parse request body + let body: { refreshToken?: string }; + + try { + body = event.body ? JSON.parse(event.body) : {}; + } catch (error) { + throw new ApiError(400, 'Invalid JSON in request body'); + } + + const { refreshToken } = body; + + if (!refreshToken) { + throw new ApiError(400, 'Refresh token is required'); + } + + // Verify refresh token + const decodedToken = await tokenService.verifyRefreshToken(refreshToken); + + if (!decodedToken || typeof decodedToken === 'string') { + throw new ApiError(401, 'Invalid or expired refresh token'); + } + + const payload = decodedToken as JwtPayload; + + if (payload.type !== 'refresh') { + throw new ApiError(401, 'Token is not a refresh token'); + } + + const userId = payload.sub; + + if (!userId) { + throw new ApiError(401, 'Invalid token payload'); + } + + // Check if user exists + const user = await prismaClient.user.findUnique({ + where: { id: parseInt(userId, 10) }, + select: { id: true, isActive: true }, + }); + + if (!user || !user.isActive) { + throw new ApiError(401, 'User not found or inactive'); + } + + // Check if refresh token exists in database and is not blacklisted + const tokenRecord = await prismaClient.token.findFirst({ + where: { + token: refreshToken, + userXid: parseInt(userId, 10), + tokenType: 'refresh', + isBlackListed: false, + }, + }); + + if (!tokenRecord) { + throw new ApiError(401, 'Refresh token is invalid or blacklisted'); + } + + // Generate new access token + const newAccessToken = await tokenService.generateAuthToken(Number(userId)); + + return { + statusCode: 200, + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }, + body: JSON.stringify({ + success: true, + message: 'Access token generated successfully', + accessToken: newAccessToken.access.token, + accessTokenExpires: newAccessToken.access.expires, + data: null, + }), + }; + }, +);