Compare commits
4 Commits
63fcd8587b
...
9c4854ce64
| Author | SHA1 | Date | |
|---|---|---|---|
| 9c4854ce64 | |||
| 9e84460a22 | |||
| 9686153a82 | |||
| 3122f34093 |
@ -9,7 +9,7 @@ export const jwtDecode = (payload: string) => {
|
|||||||
try {
|
try {
|
||||||
const decodedPayload = jwt.verify(payload, JWTKey);
|
const decodedPayload = jwt.verify(payload, JWTKey);
|
||||||
return decodedPayload as JWTAuthToken;
|
return decodedPayload as JWTAuthToken;
|
||||||
} catch (error) {
|
} catch {
|
||||||
throw new AppError(401, "Invalid or expired token", error);
|
throw new AppError(403, "Invalid or expired token");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { parse } from "cookie";
|
|||||||
|
|
||||||
export const logoutController = async (ctx: Context) => {
|
export const logoutController = async (ctx: Context) => {
|
||||||
try {
|
try {
|
||||||
const jwtToken = parse(ctx.request.headers.get("auth_token") || "")
|
const jwtToken = parse(ctx.request.headers.get("Cookie") || "")
|
||||||
.auth_token as string;
|
.auth_token as string;
|
||||||
const serviceResponse = await logoutService(jwtToken);
|
const serviceResponse = await logoutService(jwtToken);
|
||||||
return returnWriteResponse(
|
return returnWriteResponse(
|
||||||
|
|||||||
@ -4,10 +4,10 @@ import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
|||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||||
import { parse } from "cookie";
|
import { parse } from "cookie";
|
||||||
|
|
||||||
export const tokenValidationController = (ctx: Context) => {
|
export const tokenValidationController = async (ctx: Context) => {
|
||||||
try {
|
try {
|
||||||
const { auth_token } = parse(ctx.request.headers.get("cookie") || "");
|
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(
|
return returnReadResponse(
|
||||||
ctx.set,
|
ctx.set,
|
||||||
200,
|
200,
|
||||||
|
|||||||
@ -1,10 +1,33 @@
|
|||||||
|
import { AppError } from "../../../../helpers/error/instances/app";
|
||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||||
import { jwtDecode } from "../../../../helpers/http/jwt/decode";
|
import { jwtDecode } from "../../../../helpers/http/jwt/decode";
|
||||||
|
import { redis } from "../../../../utils/databases/redis/connection";
|
||||||
|
import { checkUserSessionInDBService } from "../../../userSession/services/internal/checkUserSessionInDB.service";
|
||||||
|
import { createUserSessionInRedisService } from "../../../userSession/services/internal/createUserSessionInRedis.service";
|
||||||
|
|
||||||
export const tokenValidationService = (payload: string) => {
|
export const tokenValidationService = async (payload: string) => {
|
||||||
try {
|
try {
|
||||||
if (!payload) return null;
|
if (!payload || payload.trim() === "")
|
||||||
|
throw new AppError(401, "Unauthorized: No token provided");
|
||||||
const decoded = jwtDecode(payload);
|
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");
|
||||||
|
await createUserSessionInRedisService({
|
||||||
|
userId: decoded.user.id,
|
||||||
|
sessionId: decoded.id,
|
||||||
|
validUntil: decoded.validUntil,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return decoded;
|
return decoded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ErrorForwarder(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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -4,10 +4,11 @@ import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
|||||||
import { createUserSessionRepository } from "../repositories/createUserSession.repository";
|
import { createUserSessionRepository } from "../repositories/createUserSession.repository";
|
||||||
import { redis } from "../../../utils/databases/redis/connection";
|
import { redis } from "../../../utils/databases/redis/connection";
|
||||||
import { jwtEncode } from "../../../helpers/http/jwt/encode";
|
import { jwtEncode } from "../../../helpers/http/jwt/encode";
|
||||||
|
import { createUserSessionInRedisService } from "./internal/createUserSessionInRedis.service";
|
||||||
|
|
||||||
export const createUserSessionService = async (
|
export const createUserSessionService = async (
|
||||||
userId: string,
|
userId: string,
|
||||||
userHeaderInfo: UserHeaderInformation
|
userHeaderInfo: UserHeaderInformation,
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
// set the date when the token will expire
|
// set the date when the token will expire
|
||||||
@ -29,13 +30,11 @@ export const createUserSessionService = async (
|
|||||||
const createUserSession = await createUserSessionRepository(constructData);
|
const createUserSession = await createUserSessionRepository(constructData);
|
||||||
|
|
||||||
// caching user session data into Redis
|
// caching user session data into Redis
|
||||||
const createRedisKey = `${process.env.APP_NAME}:users:${userId}:sessions:${createUserSession.id}`;
|
await createUserSessionInRedisService({
|
||||||
await redis.hset(createRedisKey, {
|
|
||||||
userId,
|
userId,
|
||||||
sessionId: createUserSession.id,
|
sessionId: createUserSession.id,
|
||||||
validUntil: createUserSession.validUntil,
|
validUntil: createUserSession.validUntil,
|
||||||
});
|
});
|
||||||
await redis.expire(createRedisKey, Number(process.env.SESSION_EXPIRE));
|
|
||||||
|
|
||||||
// create a jwt token with a payload containing the created user session, then return jwt
|
// create a jwt token with a payload containing the created user session, then return jwt
|
||||||
return jwtEncode(createUserSession);
|
return jwtEncode(createUserSession);
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
import { AppError } from "../../../../helpers/error/instances/app";
|
||||||
|
import { redis } from "../../../../utils/databases/redis/connection";
|
||||||
|
|
||||||
|
export const createUserSessionInRedisService = async ({
|
||||||
|
userId,
|
||||||
|
sessionId,
|
||||||
|
validUntil,
|
||||||
|
exp,
|
||||||
|
}: {
|
||||||
|
userId: string;
|
||||||
|
sessionId: string;
|
||||||
|
validUntil?: Date;
|
||||||
|
exp?: number;
|
||||||
|
}) => {
|
||||||
|
try {
|
||||||
|
const createRedisKey = `${process.env.APP_NAME}:users:${userId}:sessions:${sessionId}`;
|
||||||
|
await redis.hset(createRedisKey, {
|
||||||
|
userId,
|
||||||
|
sessionId,
|
||||||
|
validUntil: validUntil,
|
||||||
|
});
|
||||||
|
await redis.expire(
|
||||||
|
createRedisKey,
|
||||||
|
exp || Number(process.env.SESSION_CACHE_EXPIRE!),
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
throw new AppError(500, "Error creating user session in Redis", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user