🔒 security: add auth token validation via Redis and DB check
This commit is contained in:
@ -4,10 +4,10 @@ import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||
import { parse } from "cookie";
|
||||
|
||||
export const tokenValidationController = (ctx: Context) => {
|
||||
export const tokenValidationController = async (ctx: Context) => {
|
||||
try {
|
||||
const { auth_token } = parse(ctx.request.headers.get("cookie") || "");
|
||||
const validationResult = tokenValidationService(auth_token as string);
|
||||
const validationResult = await tokenValidationService(auth_token as string);
|
||||
return returnReadResponse(
|
||||
ctx.set,
|
||||
200,
|
||||
|
||||
@ -1,12 +1,34 @@
|
||||
import { AppError } from "../../../../helpers/error/instances/app";
|
||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||
import { jwtDecode } from "../../../../helpers/http/jwt/decode";
|
||||
import { redis } from "../../../../utils/databases/redis/connection";
|
||||
import { checkUserSessionInDBService } from "../../../userSession/services/internal/checkUserSessionInDB.service";
|
||||
|
||||
export const tokenValidationService = (payload: string) => {
|
||||
export const tokenValidationService = async (payload: string) => {
|
||||
try {
|
||||
if (!payload || payload.trim() === "")
|
||||
throw new AppError(401, "Unauthorized: No token provided");
|
||||
const decoded = jwtDecode(payload);
|
||||
|
||||
const redisValidationResult = await redis.hgetall(
|
||||
`${process.env.APP_NAME}:users:${decoded.user.id}:sessions:${decoded.id}`,
|
||||
);
|
||||
if (
|
||||
!redisValidationResult ||
|
||||
Object.keys(redisValidationResult).length === 0
|
||||
) {
|
||||
const dbValidationResult = await checkUserSessionInDBService(decoded.id);
|
||||
if (!dbValidationResult)
|
||||
throw new AppError(403, "Unauthorized: Invalid session");
|
||||
const createRedisKey = `${process.env.APP_NAME}:users:${decoded.user.id}:sessions:${decoded.id}`;
|
||||
await redis.hset(createRedisKey, {
|
||||
userId: decoded.user.id,
|
||||
sessionId: decoded.id,
|
||||
validUntil: decoded.validUntil,
|
||||
});
|
||||
await redis.expire(createRedisKey, Number(process.env.SESSION_EXPIRE));
|
||||
}
|
||||
|
||||
return decoded;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
import { AppError } from "../../../helpers/error/instances/app";
|
||||
import { userSessionModel } from "../userSession.model";
|
||||
|
||||
export const checkUserSessionRepository = async (sessionId: string) => {
|
||||
try {
|
||||
return await userSessionModel.findUnique({
|
||||
where: {
|
||||
id: sessionId,
|
||||
isAuthenticated: true,
|
||||
deletedAt: null,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
throw new AppError(500, "Database error during session validation", error);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,13 @@
|
||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||
import { checkUserSessionRepository } from "../../repositories/checkUserSession.repository";
|
||||
|
||||
export const checkUserSessionInDBService = async (
|
||||
sessionId: string,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const dbValidationResult = await checkUserSessionRepository(sessionId);
|
||||
return dbValidationResult ? true : false;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user