@replyke/express
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
101 lines (100 loc) • 4.06 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const models_1 = require("../../../models");
const models_2 = require("../../../models");
const reduceAuthenticatedUserDetails_1 = __importDefault(require("../../../helpers/reduceAuthenticatedUserDetails"));
const config_1 = require("../../../config");
exports.default = async (req, res) => {
const { refreshToken } = req.body;
const projectId = req.project.id;
const cookies = req.cookies;
const { refreshTokenSecret } = (0, config_1.getCoreConfig)();
const refreshTokenJWT = cookies?.["replyke-refresh-jwt"] || refreshToken;
if (!refreshTokenJWT) {
res.status(200).json({
user: null,
accessToken: null,
});
return;
}
try {
// Decode and verify the refresh token JWT
const decoded = jsonwebtoken_1.default.verify(refreshTokenJWT, refreshTokenSecret);
const { sub: userId, jti, projectId: decodedProjectId } = decoded;
// Invalid token
if (!userId || !jti || decodedProjectId !== projectId) {
res.status(403).json({
error: "Invalid refresh token.",
code: "auth/invalid-refresh-token",
});
return;
}
// Find the refresh token in the Token table using the `jti`
const storedToken = (await models_2.Token.findOne({
where: { id: jti, userId, projectId },
}));
// Token not found or mismatch
if (!storedToken || storedToken.refreshToken !== refreshTokenJWT) {
res.status(403).json({
error: "Refresh token not recognized.",
code: "auth/refresh-token-mismatch",
});
return;
}
// get the target model for that alias:
const SuspensionModel = models_1.User.associations.suspensions
.target;
const ActiveSuspensionModel = SuspensionModel.scope({
method: ["active", new Date()],
});
// Find user by ID
const userWithSuspensions = (await models_1.User.findByPk(userId, {
include: [
{
model: ActiveSuspensionModel,
as: "suspensions",
required: false,
},
],
}));
if (!userWithSuspensions) {
res.status(403).json({
error: "User not found.",
code: "auth/no-user-found",
});
return;
}
// Generate a new access token
const accessTokenJWT = jsonwebtoken_1.default.sign({
sub: userWithSuspensions.id, // Subject, representing the user ID
projectId, // Project ID, indicating which project this token is tied to
role: "user", // User role
aud: "replyke.com", // Audience
iss: "replyke.com", // Issuer
}, process.env.ACCESS_TOKEN_SECRET, { expiresIn: "30m" } // Access token expires in 30 minutes
);
const reducedAuthenticatedUser = (0, reduceAuthenticatedUserDetails_1.default)(userWithSuspensions);
// Send the new access token to the client
res.status(200).json({
success: true,
accessToken: accessTokenJWT,
user: reducedAuthenticatedUser,
});
userWithSuspensions.lastActive = new Date();
userWithSuspensions.save();
const { handlers } = (0, config_1.getCoreConfig)();
await handlers.requestNewAccessToken({ projectId, userId });
}
catch (err) {
console.error("Error verifying refresh token:", err);
res.status(403).json({
error: "Invalid or expired refresh token.",
code: "auth/refresh-token-invalid",
details: err.message,
});
}
};