Skip to content

Commit 68627ea

Browse files
Merge pull request #107 from GMHarish285/qse_googlerefresh3
Refresh tokens added for GoogleOAuth template
2 parents c2f2c31 + 34808eb commit 68627ea

File tree

3 files changed

+97
-57
lines changed

3 files changed

+97
-57
lines changed

templates/express_oauth_google/controller/appController.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const getUserHomePage = (req, res) => {
22
const user = req.user;
3-
const token = req.cookies?.token;
3+
const token = req.cookies?.access_token;
44
return res.send(
55
`Your name is: ${user.name}<br>Your email is: ${user.email}<br>Your token is: ${token}<br><br><a href="/auth/logout">Logout</a>`,
66
);

templates/express_oauth_google/controller/authController.js

Lines changed: 83 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,22 @@ import { errorHandlerFunc } from "../errorHandler/errorHandler.js";
55
import { googleConfig } from "../config/config.js";
66

77
const checkLogin = (req, res) => {
8-
const token = req.cookies?.token;
9-
if (token) {
8+
const accessToken = req.cookies?.access_token;
9+
const refreshToken = req.cookies?.refresh_token;
10+
11+
if (accessToken) {
1012
try {
11-
jwt.verify(token, process.env.JWT_SECRET);
13+
jwt.verify(accessToken, process.env.JWT_SECRET);
1214
return res.redirect("/");
1315
} catch (err) {
14-
errorHandlerFunc(
15-
err,
16-
"controller/authController",
17-
401,
18-
"Authentication failed",
19-
);
16+
console.log("[INFO]: Access token expired or invalid.");
2017
}
2118
}
2219

20+
if (refreshToken) {
21+
return refreshAccessToken(req, res);
22+
}
23+
2324
const options = {
2425
redirect_uri: process.env.GOOGLE_CALLBACK_URL,
2526
client_id: process.env.GOOGLE_CLIENT_ID,
@@ -40,30 +41,82 @@ const handleAuth = async (req, res) => {
4041
return res.redirect("/");
4142
}
4243

43-
// Exchange code for tokens.
44-
const { data: tokens } = await axios.post(googleConfig.tokenUrl, {
45-
code,
46-
client_id: process.env.GOOGLE_CLIENT_ID,
47-
client_secret: process.env.GOOGLE_CLIENT_SECRET,
48-
redirect_uri: process.env.GOOGLE_CALLBACK_URL,
49-
grant_type: "authorization_code",
50-
});
51-
52-
// Fetch user profile.
53-
const { data: googleUser } = await axios.get(
54-
`${googleConfig.userInfoUrl}&access_token=${tokens.access_token}`,
55-
);
56-
57-
const user = { email: googleUser.email, name: googleUser.name };
58-
const token = jwt.sign(user, process.env.JWT_SECRET, { expiresIn: "1h" });
59-
res.cookie("token", token, { httpOnly: true });
60-
// res.cookie('token', token, { httpOnly: true, secure: true }) // Use in production.
61-
return res.redirect("/");
44+
try {
45+
// Exchange code for tokens.
46+
const { data: tokens } = await axios.post(googleConfig.tokenUrl, {
47+
code,
48+
client_id: process.env.GOOGLE_CLIENT_ID,
49+
client_secret: process.env.GOOGLE_CLIENT_SECRET,
50+
redirect_uri: process.env.GOOGLE_CALLBACK_URL,
51+
grant_type: "authorization_code",
52+
});
53+
54+
// Fetch user profile.
55+
const { data: googleUser } = await axios.get(
56+
`${googleConfig.userInfoUrl}&access_token=${tokens.access_token}`,
57+
);
58+
59+
const user = { email: googleUser.email, name: googleUser.name };
60+
const accessToken = jwt.sign(user, process.env.JWT_SECRET, {
61+
expiresIn: "10s",
62+
});
63+
64+
// Set cookies for access and refresh tokens.
65+
res.cookie("access_token", accessToken, { httpOnly: true });
66+
res.cookie("refresh_token", tokens.refresh_token, { httpOnly: true });
67+
68+
return res.redirect("/");
69+
} catch (err) {
70+
errorHandlerFunc(
71+
err,
72+
res,
73+
"controller/authController.log",
74+
500,
75+
"Authentication failed",
76+
);
77+
}
78+
};
79+
80+
const refreshAccessToken = async (req, res) => {
81+
try {
82+
const refreshToken = req.cookies.refresh_token;
83+
84+
// Use refresh token to get a new access token.
85+
const { data: tokens } = await axios.post(googleConfig.tokenUrl, {
86+
client_id: process.env.GOOGLE_CLIENT_ID,
87+
client_secret: process.env.GOOGLE_CLIENT_SECRET,
88+
refresh_token: refreshToken,
89+
grant_type: "refresh_token",
90+
});
91+
92+
// Decode user information from the token.
93+
const { data: googleUser } = await axios.get(
94+
`${googleConfig.userInfoUrl}&access_token=${tokens.access_token}`,
95+
);
96+
97+
const user = { email: googleUser.email, name: googleUser.name };
98+
const newAccessToken = jwt.sign(user, process.env.JWT_SECRET, {
99+
expiresIn: "10s",
100+
});
101+
102+
// Update access token cookie.
103+
res.cookie("access_token", newAccessToken, { httpOnly: true });
104+
return res.redirect("/");
105+
} catch (err) {
106+
errorHandlerFunc(
107+
err,
108+
res,
109+
"controller/authController.log",
110+
401,
111+
"Failed to refresh access token",
112+
);
113+
}
62114
};
63115

64116
const logout = (req, res) => {
65-
res.clearCookie("token");
117+
res.clearCookie("access_token");
118+
res.clearCookie("refresh_token"); // Clear refresh token as well.
66119
return res.redirect("/");
67120
};
68121

69-
export { checkLogin, handleAuth, logout };
122+
export { checkLogin, handleAuth, logout, refreshAccessToken };

templates/express_oauth_google/middleware/authenticate.js

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,28 @@
11
import jwt from "jsonwebtoken";
2-
2+
import { refreshAccessToken } from "../controller/authController.js";
33
import { errorHandlerFunc } from "../errorHandler/errorHandler.js";
44

5-
// Cookie token authentication.
65
const authenticateUser = (req, res, next) => {
7-
const token = req.cookies?.token;
8-
if (!token) {
6+
const accessToken = req.cookies?.access_token;
7+
const refreshToken = req.cookies?.refresh_token;
8+
9+
if (!accessToken && refreshToken) {
10+
return refreshAccessToken(req, res); // Refresh access token if expired.
11+
}
12+
if (!accessToken) {
913
return res.redirect("/auth/login");
1014
}
1115

1216
try {
13-
const user = jwt.verify(token, process.env.JWT_SECRET);
17+
const user = jwt.verify(accessToken, process.env.JWT_SECRET);
1418
req.user = user;
1519
next();
1620
} catch (err) {
17-
// Renew token if it gets expired.
18-
if (err.name === "TokenExpiredError") {
19-
try {
20-
const user = jwt.decode(token);
21-
const newToken = jwt.sign(user, process.env.JWT_SECRET, {
22-
expiresIn: "1h",
23-
});
24-
res.cookie("token", newToken, { httpOnly: true });
25-
req.user = user;
26-
return next();
27-
} catch (decodeErr) {
28-
console.error(`[ERROR]: ${decodeErr.message}`);
29-
errorHandlerFunc(
30-
err,
31-
res,
32-
"middleware/authenticate.log",
33-
401,
34-
"Authentication failed",
35-
);
36-
return res.redirect("/auth/login");
37-
}
21+
if (err.name === "TokenExpiredError" && refreshToken) {
22+
console.log("[INFO]: Access token expired. Refreshing...");
23+
return refreshAccessToken(req, res);
3824
}
25+
3926
errorHandlerFunc(
4027
err,
4128
res,

0 commit comments

Comments
 (0)