const jwt = require("jsonwebtoken") const crypto = require("node:crypto") const security = require("../modules/security") const tokenRepo = require("../repositories/refreshTokensRepo") const { DefaultError } = require("../errors/errors") const privateKey = security.readPrivateKey() const publicKey = security.readPublicKey() async function signToken(user) { try { const payload = { id: user.id, identifier: user.identifier, displayName: user.displayName, avatarUrl: user.avatarUrl, role: user.role } const token = await jwt.sign(payload, privateKey, { algorithm: "RS256", issuer: process.env.FQDN, expiresIn: parseInt(process.env.ACCESS_TOKEN_EXPIRY) }) return token } catch (error) { throw error } } async function verifyAccessToken(token) { try { const result = jwt.verify(token, publicKey, { algorithms: ["RS256"], issuer: process.env.FQDN }) return result } catch (error) { throw error } } async function signRefreshToken(userId) { try { const isTokenExisting = await tokenRepo.findByUserId(userId) if (!Array.isArray(isTokenExisting)) { await tokenRepo.removeByUserId(userId) } const now = Date.now() const expiresIn = parseInt(process.env.REFRESH_TOKEN_EXPIRY) const expiresAtInMs = new Date(now + (expiresIn * 1000)) const token = jwt.sign( { userId }, privateKey, { algorithm: "RS256", issuer: process.env.FQDN, expiresIn: expiresIn } ) const hash = crypto.createHash("sha256").update(token).digest("hex") await tokenRepo.create(userId, hash, expiresAtInMs) return token } catch (error) { throw error } } async function revokeRefreshToken(token) { try { return await tokenRepo.removeByTokenHash(token) } catch (error) { throw error } } async function verifyRefreshToken(token) { try { const result = jwt.verify(token, publicKey, { algorithms: ["RS256"], issuer: process.env.FQDN }) if (!result) { throw new DefaultError(500, "Internal Server Error") } const hash = crypto.createHash("sha256").update(token).digest("hex") const refreshTokenInDb = await tokenRepo.findByTokenHash(hash) if (refreshTokenInDb == null) { throw new DefaultError(403, "Bad refresh token", "Refresh token doesn't exists") } return result } catch (error) { throw error } } async function verifyAccessTokenFromServer(token) { // TO-DO: Integrate server federation } module.exports = { signToken, signRefreshToken, verifyAccessToken, revokeRefreshToken, verifyRefreshToken, }