import { randomBytes } from "node:crypto"; import DayJs from "dayjs"; import { inject, injectable } from "inversify"; import jwt, { SignOptions, TokenExpiredError } from "jsonwebtoken"; import { TokenRepository } from "./token.repository"; import { AuthTokenPayload, TokenType } from "../../common/types/jwt.type"; import { jwtExpiredErr } from "../../core/app/app.errors"; import { Logger } from "../../core/logging/logger"; import { IOCTYPES } from "../../IOC/ioc.types"; @injectable() export class TokenService { private logger = new Logger(TokenService.name); @inject(IOCTYPES.TokenRepository) private tokenRepository: TokenRepository; private jwtSecret: string = process.env.JWT_SECRET; private jwt_access_expire: string = process.env.JWT_EXPIRE_ACCESS || "2"; //minutes private jwt_refresh_expire: string = process.env.JWT_EXPIRE_REFRESH || "2"; //day public _generateToken(type: TokenType, payload: AuthTokenPayload, option?: SignOptions) { if (type == "Access" && option?.expiresIn) return jwt.sign(payload, this.jwtSecret, { ...option }); const refToken = randomBytes(24).toString("hex"); return refToken; } public async generateAuthTokens(payload: AuthTokenPayload) { const accessToken = this._generateToken("Access", payload, { expiresIn: `${this.jwt_access_expire}m` }); const refreshToken = this._generateToken("Refresh", payload); const RefreshExpire = DayJs().add(+this.jwt_refresh_expire, "day").toDate(); const oldToken = await this.tokenRepository.findByUserId(payload.sub); if (oldToken) { await this.tokenRepository.delete(oldToken._id.toString()); } await this.tokenRepository.model.create({ refreshToken, userId: payload.sub, refreshTokenExpire: RefreshExpire }); const tokens = { accessToken: { token: accessToken, expires: DayJs().add(+this.jwt_access_expire, "m").unix().toString(), }, refreshToken: { token: refreshToken, expires: DayJs().add(+this.jwt_refresh_expire, "day").unix().toString(), }, }; return tokens; } public async revokeTokens(id: string) { // const deletedToken = await this.tokenRepository.delete(id); // if (!deletedToken) return false; // return true; return !!(await this.tokenRepository.delete(id)); } public verifyToken(token: string): AuthTokenPayload { try { const decoded = jwt.verify(token, this.jwtSecret); return decoded as AuthTokenPayload; } catch (error) { if (error instanceof TokenExpiredError) throw new jwtExpiredErr(); this.logger.error("error in jwt verify", error); throw error; } } }