Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Implement Google Oauth login #2278

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from

Conversation

listiclehub1
Copy link

Date: 02/12/2024

Developer Name: Utkarsh Bansal


Issue Ticket Number

#2216

Description

If the person is a developer they have to login via GitHub but a non developer should be able to login by their Google Account.

Documentation Updated?

  • Yes
  • No

Under Feature Flag

  • Yes
  • No

Database Changes

  • Yes
  • No

Breaking Changes

  • Yes
  • No

Development Tested?

  • Yes
  • No

Screenshots

Screenshot 1
google-login-test-local.mp4

Test Coverage

Screenshot 1 Screenshot 2024-12-02 at 3 28 25 PM

Additional Notes

Need to generate oauth credentials for staging as well as prod from google cloud console.

scope: ["email"],
state: redirectURL,
})(req, res, next);
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • can we remove the else block here? as we're doing an early return above?

Comment on lines +29 to +40
try {
const redirectUrl = new URL(req.query.state);

if (`.${redirectUrl.hostname}`.endsWith(`.${rdsUiUrl.hostname}`)) {
// Matching *.realdevsquad.com
authRedirectionUrl = redirectUrl;
} else {
logger.error(`Malicious redirect URL provided URL: ${redirectUrl}, Will redirect to RDS`);
}
} catch (error) {
logger.error("Invalid redirect URL provided", error);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • do we need a try catch here?

Comment on lines +43 to +80
return passport.authenticate("google", { session: false }, async (err, accessToken, user) => {
if (err) {
logger.error(err);
return res.boom.unauthorized("User cannot be authenticated");
}
const userData = {
email: user.emails[0].value,
created_at: Date.now(),
updated_at: null,
};

const userDataFromDB = await users.fetchUser({ email: userData.email });

if (userDataFromDB.userExists) {
if (userDataFromDB.user.roles.developer === true) {
const errorMessage = encodeURIComponent("Google login is restricted for developer role.");
return res.redirect(`${authRedirectionUrl}?error=${errorMessage}`);
}
}

const { userId, incompleteUserDetails } = await users.addOrUpdate(userData);

const token = authService.generateAuthToken({ userId });

const cookieOptions = {
domain: rdsUiUrl.hostname,
expires: new Date(Date.now() + config.get("userToken.ttl") * 1000),
httpOnly: true,
secure: true,
sameSite: "lax",
};

res.cookie(config.get("userToken.cookieName"), token, cookieOptions);

if (incompleteUserDetails) authRedirectionUrl = "https://my.realdevsquad.com/new-signup";

return res.redirect(authRedirectionUrl);
})(req, res, next);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • let's move the logic to a different function instead of adding it inside the callback function of the passport.authenticate method.

github_created_at: Number(new Date(user._json.created_at).getTime()),
github_user_id: user.id,
created_at: Date.now(),
updated_at: null,
};

if (userData.email === null) {
const res = await fetch("https://api.github.com/user/emails", {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • let's move the base path (https://api.github.com) inside an env variable, to allow it to be configurable for different environments if the situation arises.

github_created_at: Number(new Date(user._json.created_at).getTime()),
github_user_id: user.id,
created_at: Date.now(),
updated_at: null,
};

if (userData.email === null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • this will also check for undefined along with null.
Suggested change
if (userData.email === null) {
if (!userData.email) {

if (user && !user.empty && user.docs !== null) {
await userModel.doc(user.docs[0].id).set({ ...userData, updated_at: Date.now() }, { merge: true });
const { created_at: createdAt, ...updatedUserData } = userData;
await userModel.doc(user.docs[0].id).set({ ...updatedUserData, updated_at: Date.now() }, { merge: true });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • can user.docs be empty? if yes are we handling that case?

user = await userModel.where("github_id", "==", userData.github_id).limit(1).get();
}

if (userData.email && (!user || (user && user.empty))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • if we're already doing a !user check do we need to do (user && user.empty)) can we just do !user || user.empty ?

@@ -9,6 +9,10 @@

router.get("/github/callback", auth.githubAuthCallback);

router.get("/google/login", auth.googleAuthLogin);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
@@ -9,6 +9,10 @@

router.get("/github/callback", auth.githubAuthCallback);

router.get("/google/login", auth.googleAuthLogin);

router.get("/google/callback", auth.googleAuthCallback);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants