propro-utils 1.3.14 → 1.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/src/server/index.js
CHANGED
|
@@ -4,8 +4,90 @@ const {
|
|
|
4
4
|
exchangeToken,
|
|
5
5
|
VerifyAccount,
|
|
6
6
|
} = require("./middleware/verifyToken");
|
|
7
|
-
const {refreshTokenMiddleware} = require("./middleware");
|
|
8
|
-
|
|
7
|
+
// const {refreshTokenMiddleware} = require("./middleware");
|
|
8
|
+
|
|
9
|
+
const refreshLimiter = rateLimit({
|
|
10
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
11
|
+
max: 100, // Limit each IP to 100 requests per 15 minutes
|
|
12
|
+
message: "Too many refresh requests from this IP, please try again after 15 minutes",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const refreshTokenCache = new Map();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Middleware to refresh access token using refresh token.
|
|
19
|
+
*
|
|
20
|
+
* @param {Object} req - The request object.
|
|
21
|
+
* @param {Object} res - The response object.
|
|
22
|
+
* @param {Function} next - The next middleware function.
|
|
23
|
+
* @returns {void}
|
|
24
|
+
*/
|
|
25
|
+
async function refreshTokenMiddleware(req, res, next) {
|
|
26
|
+
refreshLimiter(req, res, async () => {
|
|
27
|
+
const refreshToken = req.cookies['x-refresh-token'];
|
|
28
|
+
if (!refreshToken) {
|
|
29
|
+
return res.status(401).json({ error: "No refresh token provided" });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!isValidRefreshTokenFormat(refreshToken)) {
|
|
33
|
+
return res.status(400).json({ error: "Invalid refresh token format" });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (refreshTokenCache.has(refreshToken)) {
|
|
37
|
+
req.newAccessToken = refreshTokenCache.get(refreshToken);
|
|
38
|
+
return next();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const response = await axios.post(
|
|
43
|
+
`${process.env.AUTH_URL}/oauth/token`,
|
|
44
|
+
new URLSearchParams({
|
|
45
|
+
grant_type: "refresh_token",
|
|
46
|
+
refresh_token: refreshToken,
|
|
47
|
+
client_id: process.env.CLIENT_ID,
|
|
48
|
+
client_secret: process.env.CLIENT_SECRET,
|
|
49
|
+
}),
|
|
50
|
+
{ headers: { "Content-Type": "application/x-www-form-urlencoded" } }
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
if (response.data && response.data.access_token) {
|
|
54
|
+
refreshTokenCache.set(refreshToken, response.data.access_token);
|
|
55
|
+
req.newAccessToken = response.data.access_token;
|
|
56
|
+
next();
|
|
57
|
+
} else {
|
|
58
|
+
res.status(401).json({ error: "Unable to refresh token" });
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const statusCode = error.response?.status || 500;
|
|
62
|
+
res.status(statusCode).json({ error: error.response?.data?.error || "Error refreshing token" });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Checks if the given token has a valid refresh token format.
|
|
69
|
+
*
|
|
70
|
+
* @param {string} token - The token to validate.
|
|
71
|
+
*
|
|
72
|
+
* @return {boolean} - Returns true if the token has a valid refresh token format, otherwise false.
|
|
73
|
+
*/
|
|
74
|
+
function isValidRefreshTokenFormat(token) {
|
|
75
|
+
const jwtPattern = /^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+$/;
|
|
76
|
+
return jwtPattern.test(token);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Middleware for handling authentication and authorization.
|
|
80
|
+
*
|
|
81
|
+
* @param {object} [options={}] - The options for configuring the authentication middleware.
|
|
82
|
+
* @param {string} [options.secret="RESTFULAPIs"] - The secret key used for authentication.
|
|
83
|
+
* @param {string} [options.authUrl=process.env.AUTH_URL] - The authentication URL.
|
|
84
|
+
* @param {string} [options.clientId=process.env.CLIENT_ID] - The client ID.
|
|
85
|
+
* @param {string} [options.clientSecret=process.env.CLIENT_SECRET] - The client secret.
|
|
86
|
+
* @param {string} [options.clientUrl=process.env.CLIENT_URL] - The client URL.
|
|
87
|
+
* @param {string} [options.redirectUri=process.env.REDIRECT_URI] - The redirect URI.
|
|
88
|
+
* @param {string} [options.appName=process.env.APP_NAME] - The application name.
|
|
89
|
+
* @returns {Function} - Express middleware function.
|
|
90
|
+
*/
|
|
9
91
|
function proproAuthMiddleware(options = {}) {
|
|
10
92
|
const {
|
|
11
93
|
secret = "RESTFULAPIs",
|
|
@@ -19,44 +101,6 @@ function proproAuthMiddleware(options = {}) {
|
|
|
19
101
|
|
|
20
102
|
return async (req, res, next) => {
|
|
21
103
|
try {
|
|
22
|
-
let token;
|
|
23
|
-
if (req.headers.authorization?.startsWith("Bearer ")) {
|
|
24
|
-
token = req.headers.authorization.split(" ")[1];
|
|
25
|
-
} else if (req.cookies && req.cookies['x-access-token']) {
|
|
26
|
-
token = req.cookies['x-access-token'];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (token) {
|
|
30
|
-
console.log("verifying access token", token);
|
|
31
|
-
const verifiedToken = await verifyJWT(token);
|
|
32
|
-
console.log("verifiedToken", verifiedToken);
|
|
33
|
-
if (verifiedToken) {
|
|
34
|
-
req.account = verifiedToken;
|
|
35
|
-
return next();
|
|
36
|
-
} else if (req.cookies && req.cookies['x-refresh-token']) {
|
|
37
|
-
const refreshToken = req.cookies['x-refresh-token'];
|
|
38
|
-
if (refreshToken) {
|
|
39
|
-
const newTokenData = await refreshTokenMiddleware(req, res, next);
|
|
40
|
-
if (newTokenData) {
|
|
41
|
-
res.cookie("x-refresh-token", newTokenData.tokens.refresh.token, {
|
|
42
|
-
httpOnly: true,
|
|
43
|
-
secure: process.env.NODE_ENV === "production",
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
res.cookie("x-access-token", newTokenData.tokens.access.token, {
|
|
47
|
-
httpOnly: true,
|
|
48
|
-
secure: process.env.NODE_ENV === "production",
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
req.account = verifyJWT(newTokenData.tokens.access.token, secret);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
} else {
|
|
56
|
-
req.account = undefined;
|
|
57
|
-
res.status(401).send("Unauthorized: Invalid or expired token");
|
|
58
|
-
}
|
|
59
|
-
|
|
60
104
|
if (!["/api/auth", "/api/callback"].includes(req.path)) {
|
|
61
105
|
return next();
|
|
62
106
|
}
|
|
@@ -106,4 +150,4 @@ function proproAuthMiddleware(options = {}) {
|
|
|
106
150
|
};
|
|
107
151
|
}
|
|
108
152
|
|
|
109
|
-
module.exports = proproAuthMiddleware;
|
|
153
|
+
module.exports = {proproAuthMiddleware, refreshTokenMiddleware};
|
|
@@ -31,20 +31,20 @@ const refreshTokenMiddleware = async (req, res, next) => {
|
|
|
31
31
|
|
|
32
32
|
console.log("refreshToken", refreshToken);
|
|
33
33
|
if (!refreshToken) {
|
|
34
|
-
|
|
34
|
+
res.status(401).json({ error: "No refresh token provided" });
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
console.log("isValidRefreshTokenFormat(refreshToken)", isValidRefreshTokenFormat(refreshToken));
|
|
38
38
|
|
|
39
39
|
if (!isValidRefreshTokenFormat(refreshToken)) {
|
|
40
|
-
|
|
40
|
+
res.status(400).json({ error: "Invalid refresh token format" });
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
console.log("refreshTokenCache.has(refreshToken)", refreshTokenCache.has(refreshToken));
|
|
44
44
|
|
|
45
45
|
if (refreshTokenCache.has(refreshToken)) {
|
|
46
46
|
req.newAccessToken = refreshTokenCache.get(refreshToken);
|
|
47
|
-
|
|
47
|
+
next();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
console.log("process.env.AUTH_URL", process.env.AUTH_URL);
|
|
@@ -66,14 +66,14 @@ const refreshTokenMiddleware = async (req, res, next) => {
|
|
|
66
66
|
if (response.data && response.data.access_token) {
|
|
67
67
|
refreshTokenCache.set(refreshToken, response.data.access_token);
|
|
68
68
|
req.newAccessToken = response.data.access_token;
|
|
69
|
-
|
|
69
|
+
next();
|
|
70
70
|
} else {
|
|
71
|
-
|
|
71
|
+
res.status(401).json({ error: "Unable to refresh token" });
|
|
72
72
|
}
|
|
73
73
|
} catch (error) {
|
|
74
74
|
const statusCode = error.response?.status || 500;
|
|
75
75
|
const message = error.response?.data?.error || "Error refreshing token";
|
|
76
|
-
|
|
76
|
+
res.status(statusCode).json({ error: message });
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
79
|
};
|