Skip to content
Snippets Groups Projects
Verified Commit 2c62841b authored by Park JongBeum's avatar Park JongBeum
Browse files

feat: renew access token by refresh token

parent cc911d5c
Branches
No related tags found
No related merge requests found
...@@ -33,8 +33,6 @@ ...@@ -33,8 +33,6 @@
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"mongoose": "^8.0.0", "mongoose": "^8.0.0",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"passport": "^0.6.0",
"passport-jwt": "^4.0.1",
"pug": "^3.0.2", "pug": "^3.0.2",
"puppeteer": "^21.5.0", "puppeteer": "^21.5.0",
"socket.io": "^4.7.2" "socket.io": "^4.7.2"
......
...@@ -7,7 +7,7 @@ import dotenv from "dotenv"; ...@@ -7,7 +7,7 @@ import dotenv from "dotenv";
import mongoose from "mongoose"; import mongoose from "mongoose";
import CustomError from "./modules/error.js"; import CustomError from "./modules/error.js";
import router from "./routes/index.js"; import router from "./routes/index.js";
import passport from "passport"; // import passport from "passport";
import cors from "cors"; import cors from "cors";
import http from "http"; import http from "http";
import socketHandler from "./socket/socketManager.js"; import socketHandler from "./socket/socketManager.js";
...@@ -81,7 +81,7 @@ app.use(express.urlencoded({ extended: true })); ...@@ -81,7 +81,7 @@ app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "../public"))); app.use(express.static(path.join(__dirname, "../public")));
app.use(cookieParser()); app.use(cookieParser());
// Passport // Passport
app.use(passport.initialize()); // app.use(passport.initialize());
// Session // Session
// app.use(session({ // app.use(session({
......
import User from "../schemas/user.js"; import jwt from "jsonwebtoken";
import passport from "passport"; import { AccessToken, RefreshToken } from "../modules/token.js";
import { Strategy as JwtStrategy, ExtractJwt } from "passport-jwt";
const verifyToken = (req, res, next) => {
passport.use( const token = req.headers["x-access-token"];
new JwtStrategy(
{ try {
jwtFromRequest: ExtractJwt.fromHeader("x-access-token"), if (!token) throw new TokenNotProvidedError();
// if token is in cookie
// jwtFromRequest: (req) => (req && req.cookies) ? req.cookies['X-Access-Token'] : null, req.decoded = jwt.verify(token, process.env.JWT_SECRET_KEY);
issuer: process.env.ISSUER, console.log("Access Token Verified");
audience: process.env.AUDIENCE,
secretOrKeyProvider: (req, rawJwtToken, done) => { req.user = {
done(null, process.env.SECRET); usermail: req.decoded["usermail"],
}, nickname: req.decoded["nickname"],
}, };
async (jwt_payload, done) => { return next();
} catch (e) {
if (e.name === "TokenExpiredError") {
console.log("Access Token Expired");
// Read Refresh Token from Cookie
const refreshToken = req.cookies["X-Refresh-Token"];
if (refreshToken) {
try { try {
const user = await User.findOne() console.log("Refresh Token Found");
.byUsermail(jwt_payload.usermail) req.decoded = jwt.verify(refreshToken, process.env.JWT_SECRET_KEY);
.populate("scores highestScore") console.log("Refresh Token Verified");
.exec(); req.user = {
if (user === null) return done(null, false); usermail: req.decoded["usermail"],
return done(null, user); nickname: req.decoded["nickname"],
};
console.log("New Access Token Generated");
res.header(
"X-Access-Token",
new AccessToken(req.user.usermail, req.user.nickname).generate()
);
return next();
} catch (e) { } catch (e) {
return done(e, false); // Remove Refresh Token from Cookie
console.log("Refresh Token Expired");
console.log("Refresh Token Removed");
// This will only work on production
// return res.redirect("/logout");
return res.redirect("/api/auth/signout");
} }
} else console.log("Refresh Token Not Found" + refreshToken);
} }
) return Object.prototype.hasOwnProperty.call(errorHandlers, e.name)
? errorHandlers[e.name](res, e)
: next(e);
}
};
const verifySocketToken = (socket, next) => {
// for postman testing, access_token is used instead of auth.token
const token =
socket.handshake.auth.token || socket.handshake.headers.access_token;
try {
if (!token) throw new TokenNotProvidedError();
socket.data.decoded = jwt.verify(token, process.env.JWT_SECRET_KEY);
socket.data.user = {
usermail: socket.data.decoded["usermail"],
nickname: socket.data.decoded["nickname"],
};
console.log(
`User ${socket.data.user.usermail}(${socket.data.user.nickname}) connected (socketid: ${socket.id})`
); );
export default passport.authenticate("jwt", { session: false }); return next();
} catch (e) {
if (e.name === "TokenExpiredError") {
return next(new Error("토큰이 만료되었습니다."));
}
// 토큰의 비밀키가 일치하지 않는 경우
if (e.name === "JsonWebTokenError") {
return next(new Error("유효하지 않은 토큰입니다."));
}
return next(e);
}
};
class TokenNotProvidedError extends Error {
constructor(message) {
super(message);
this.name = "TokenNotProvidedError";
}
}
const errorHandlers = {
TokenNotProvidedError: (res, error) =>
res.status(403).json({
name: error.name,
message: "토큰이 제공되지 않았습니다.",
}),
TokenExpiredError: (res, error) =>
res.status(419).json({
name: error.name,
message: "토큰이 만료되었습니다.",
}),
JsonWebTokenError: (res, error) =>
res.status(401).json({
name: error.name,
message: "유효하지 않은 토큰입니다.",
}),
};
export default verifyToken;
export { verifySocketToken };
...@@ -22,7 +22,7 @@ class AccessToken extends Token { ...@@ -22,7 +22,7 @@ class AccessToken extends Token {
generate() { generate() {
return jwt.sign( return jwt.sign(
{ usermail: this.usermail, nickname: this.nickname }, { usermail: this.usermail, nickname: this.nickname },
process.env.SECRET, process.env.JWT_SECRET_KEY,
{ {
subject: this.usermail, subject: this.usermail,
expiresIn: "1h", expiresIn: "1h",
...@@ -41,7 +41,7 @@ class RefreshToken extends Token { ...@@ -41,7 +41,7 @@ class RefreshToken extends Token {
generate() { generate() {
return jwt.sign( return jwt.sign(
{ usermail: this.usermail, nickname: this.nickname }, { usermail: this.usermail, nickname: this.nickname },
process.env.SECRET, process.env.JWT_SECRET_KEY,
{ {
subject: this.usermail, subject: this.usermail,
expiresIn: "14d", expiresIn: "14d",
......
import { Router } from "express"; import { Router } from "express";
import crypto from "crypto"; import crypto from "crypto";
import passport from "passport";
import { Strategy as JwtStrategy, ExtractJwt } from "passport-jwt";
import Joi from "joi"; import Joi from "joi";
import User from "../schemas/user.js"; import User from "../schemas/user.js";
import CustomError from "../modules/error.js"; import CustomError from "../modules/error.js";
......
...@@ -30,7 +30,10 @@ router.get("/rank", async (req, res, next) => { ...@@ -30,7 +30,10 @@ router.get("/rank", async (req, res, next) => {
router.get("/history", authenticator, async (req, res, next) => { router.get("/history", authenticator, async (req, res, next) => {
try { try {
return res.status(200).json(req.user.scores); const result = await User.findOne({ usermail: req.user.usermail })
.populate("scores highestScore")
.exec();
return res.status(200).json(result);
} catch (e) { } catch (e) {
next(e); next(e);
} }
......
...@@ -1751,7 +1751,7 @@ jsonfile@^4.0.0: ...@@ -1751,7 +1751,7 @@ jsonfile@^4.0.0:
optionalDependencies: optionalDependencies:
graceful-fs "^4.1.6" graceful-fs "^4.1.6"
jsonwebtoken@^9.0.0, jsonwebtoken@^9.0.2: jsonwebtoken@^9.0.2:
version "9.0.2" version "9.0.2"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
...@@ -2324,28 +2324,6 @@ parseurl@~1.3.3: ...@@ -2324,28 +2324,6 @@ parseurl@~1.3.3:
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
passport-jwt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.1.tgz#c443795eff322c38d173faa0a3c481479646ec3d"
integrity sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==
dependencies:
jsonwebtoken "^9.0.0"
passport-strategy "^1.0.0"
passport-strategy@1.x.x, passport-strategy@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==
passport@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/passport/-/passport-0.6.0.tgz#e869579fab465b5c0b291e841e6cc95c005fac9d"
integrity sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==
dependencies:
passport-strategy "1.x.x"
pause "0.0.1"
utils-merge "^1.0.1"
path-exists@^4.0.0: path-exists@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
...@@ -2381,11 +2359,6 @@ path-type@^4.0.0: ...@@ -2381,11 +2359,6 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
pause@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d"
integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==
pend@~1.2.0: pend@~1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
...@@ -3117,7 +3090,7 @@ util-deprecate@^1.0.1: ...@@ -3117,7 +3090,7 @@ util-deprecate@^1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
utils-merge@1.0.1, utils-merge@^1.0.1: utils-merge@1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment