Skip to content

Commit

Permalink
Merge branch 'feature-users-service' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
manuandru committed Jul 18, 2023
2 parents 0a3593a + 5fc01e0 commit 1f24353
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 50 deletions.
31 changes: 7 additions & 24 deletions services/users/src/controllers/user-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { UserRepository } from "../repositories/user-repository";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { decode } from "punycode";
import { generateAccessToken } from "../utils/jwt";

/**
* The controller of a generic entity.
Expand Down Expand Up @@ -60,25 +61,7 @@ export class UserController {
}

async refreshToken(req: Request, res: Response) {
// Check if the access token is present
if (!req.cookies.jwt) {
return res.status(403).send("Access token not valid");
}

// Check if the access token is valid
try {
jwt.verify(req.cookies.jwt, process.env.ACCESS_TOKEN_SECRET || "access");
res.status(403).send("Access token is valid yet");
return;
} catch (err) {}

// Retrieve the user from the database
const user = await this.userRepository.getUserByAccessToken(
req.cookies.jwt
);
if (!user) {
return res.status(403).send("Access token not valid");
}
const user = req.user;

// Retrieve the refresh token from the database
const refreshToken = await this.userRepository.getRefreshTokenFromUser(
Expand All @@ -91,7 +74,7 @@ export class UserController {
// Check if the refresh token is valid and create a new access token
try {
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET || "refresh");
const accessToken = this.userRepository.generateAccessToken(user);
const accessToken = generateAccessToken(user);
console.log("New Access token:", accessToken);
res.cookie("jwt", accessToken, { httpOnly: true, secure: true }).send();
} catch (err) {
Expand All @@ -100,14 +83,14 @@ export class UserController {
}

async logout(req: Request, res: Response) {
const user = await this.userRepository.getUserByAccessToken(
req.cookies.jwt
);
const user = req.user;
if (!user) {
return res.status(403).send("Access token not valid");
}
this.userRepository.deleteRefreshTokenOfUser(user.username);

res.clearCookie("jwt").status(200).send();
res.clearCookie("jwt").status(200).json({
message: "User logged out",
});
}
}
29 changes: 3 additions & 26 deletions services/users/src/repositories/user-repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { User } from "../models/user-model";
import jwt from "jsonwebtoken";
import { generateAccessToken, generateRefreshToken } from "../utils/jwt";

export class UserRepository {
async getUsers() {
Expand All @@ -19,31 +20,15 @@ export class UserRepository {
}

async createAccessAndRefreshToken(user: any) {
const accessToken = this.generateAccessToken(user);
const refreshToken = this.generateRefreshToken(user);
const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);

user.refreshToken = refreshToken;
await user.save();

return accessToken;
}

generateAccessToken(user: any) {
return jwt.sign(
{ username: user.username, email: user.email, id: user._id },
process.env.ACCESS_TOKEN_SECRET || "access",
{ expiresIn: "15s" }
);
}

generateRefreshToken(user: any) {
return jwt.sign(
{ username: user.username, email: user.email, id: user._id },
process.env.REFRESH_TOKEN_SECRET || "refresh",
{ expiresIn: "1d" }
);
}

async getRefreshTokenFromUser(username: string): Promise<string | null> {
const refreshToken = await User.findOne(
{ username: username },
Expand All @@ -52,14 +37,6 @@ export class UserRepository {
return refreshToken?.refreshToken || null;
}

async getUserByAccessToken(accessToken: string) {
const decodedAccessToken: any = jwt.decode(accessToken);
if (!decodedAccessToken) {
return null;
}
return await User.findOne({ username: decodedAccessToken.username });
}

async deleteRefreshTokenOfUser(username: string) {
return await User.updateOne({ username: username }, { refreshToken: "" });
}
Expand Down
4 changes: 4 additions & 0 deletions services/users/src/routes/user-router.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Router } from "express";
import { UserController } from "../controllers/user-controller";
import { jwtInvalidTokenRequired, jwtValidTokenRequired } from "../utils/jwt";

const userController = new UserController();

Expand All @@ -9,12 +10,15 @@ const userController = new UserController();
const userRouter = Router();

userRouter.route("/login").post((req, res) => userController.login(req, res));

userRouter.use("/logout", jwtValidTokenRequired);
userRouter.route("/logout").post((req, res) => userController.logout(req, res));

userRouter
.route("/register")
.post((req, res) => userController.register(req, res));

userRouter.use("/refresh-token", jwtInvalidTokenRequired);
userRouter
.route("/refresh-token")
.post((req, res) => userController.refreshToken(req, res));
Expand Down
83 changes: 83 additions & 0 deletions services/users/src/utils/jwt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Request } from "express";
import jwt from "jsonwebtoken";

type UserJWTInfo = {
id: string;
username: string;
email: string;
};

declare global {
namespace Express {
interface Request {
user: UserJWTInfo;
}
}
}

export const generateAccessToken = (user: any) => {
return jwt.sign(
{ username: user.username, email: user.email, id: user._id } as UserJWTInfo,
process.env.ACCESS_TOKEN_SECRET || "access",
{ expiresIn: "15s" }
);
};

export const generateRefreshToken = (user: any) => {
return jwt.sign(
{ username: user.username, email: user.email, id: user._id } as UserJWTInfo,
process.env.REFRESH_TOKEN_SECRET || "refresh",
{ expiresIn: "1d" }
);
};

export const jwtValidTokenRequired = (req: Request, res: any, next: any) => {
console.log("[JWT-Middleware] - Checking if JWT Token is valid");
const accessToken = req.cookies.jwt;
if (!accessToken) {
return res
.status(401)
.json({ message: "JWT Token Missing - Unauthorized" });
}
try {
const decoded = jwt.verify(
accessToken,
process.env.ACCESS_TOKEN_SECRET || "access"
) as any;
console.log("Decoded JWT Token:", decoded);
req.user = {
id: decoded.id,
username: decoded.username,
email: decoded.email,
};
next();
} catch (e) {
return res
.status(401)
.json({ message: "JWT Token Invalid - Unauthorized", error: e });
}
};

export const jwtInvalidTokenRequired = (req: Request, res: any, next: any) => {
console.log("[JWT-Middleware] - Checking if JWT Token is invalid");
const accessToken = req.cookies.jwt;
if (!accessToken) {
return res
.status(401)
.json({ message: "JWT Token Missing - Unauthorized" });
}
try {
jwt.verify(accessToken, process.env.ACCESS_TOKEN_SECRET || "access");
return res
.status(401)
.json({ message: "JWT Token Valid Yet - Unauthorized" });
} catch (e) {
const user = jwt.decode(accessToken) as any;
req.user = {
id: user.id,
username: user.username,
email: user.email,
};
next();
}
};

0 comments on commit 1f24353

Please sign in to comment.