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

[F] Google OAuth lib parity with investigations-client #392

Merged
merged 2 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/dev-pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
--build-arg NEXT_PUBLIC_DEBUG_LOGGING=false \
--build-arg CLOUD_ENV=DEV \
--build-arg NEXT_PUBLIC_GOOGLE_APP_ID=688095955960-t0fpaj4ec3gh5vsr9lhg8govapk2oeo9.apps.googleusercontent.com \
--build-arg GOOGLE_APP_SECRET=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 \
--build-arg NEXT_PUBLIC_CONTACT_FORM_POST_URL=https://api-dev.rubinobs.com/actions/contact-form/send \
--build-arg NEXT_PUBLIC_PLAUSIBLE_DOMAIN= \
--build-arg NEXT_PREVIEW_SLUG=preview-in-craft-cms \
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/dev-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
--build-arg CLOUD_ENV=DEV \
--build-arg NEXT_PUBLIC_BASE_URL=https://dev.rubinobs.com \
--build-arg NEXT_PUBLIC_GOOGLE_APP_ID=688095955960-t0fpaj4ec3gh5vsr9lhg8govapk2oeo9.apps.googleusercontent.com \
--build-arg GOOGLE_APP_SECRET=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 \
--build-arg NEXT_PUBLIC_CONTACT_FORM_POST_URL=https://api-dev.rubinobs.com/actions/contact-form/send \
--build-arg NEXT_PUBLIC_PLAUSIBLE_DOMAIN= \
--build-arg NEXT_PREVIEW_SLUG=preview-in-craft-cms \
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/master-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ jobs:
--build-arg NEXT_PUBLIC_DEBUG_LOGGING=false \
--build-arg CLOUD_ENV=INT \
--build-arg NEXT_PUBLIC_BASE_URL=https://int.rubinobs.dev \
--build-arg NEXT_PUBLIC_GOOGLE_APP_ID=688095955960-t0fpaj4ec3gh5vsr9lhg8govapk2oeo9.apps.googleusercontent.com \
--build-arg NEXT_PUBLIC_GOOGLE_APP_ID=422617727806-q7opitpsisom3fekpplsh8b77s0oe6n2.apps.googleusercontent.com \
--build-arg GOOGLE_APP_SECRET=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 \
--build-arg NEXT_PUBLIC_CONTACT_FORM_POST_URL=https://api-int.rubinobs.dev/actions/contact-form/send \
--build-arg NEXT_PUBLIC_PLAUSIBLE_DOMAIN= \
--build-arg NEXT_PREVIEW_SLUG=preview-in-craft-cms \
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/master-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ jobs:
--build-arg EDC_LOGGER_API_URL=https://us-central1-skyviewer.cloudfunctions.net/edc-logger \
--build-arg NEXT_PUBLIC_DEBUG_LOGGING=false \
--build-arg CLOUD_ENV=INT \
--build-arg NEXT_PUBLIC_GOOGLE_APP_ID=688095955960-t0fpaj4ec3gh5vsr9lhg8govapk2oeo9.apps.googleusercontent.com \
--build-arg NEXT_PUBLIC_GOOGLE_APP_ID=422617727806-q7opitpsisom3fekpplsh8b77s0oe6n2.apps.googleusercontent.com \
--build-arg GOOGLE_APP_SECRET=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 \
--build-arg NEXT_PUBLIC_CONTACT_FORM_POST_URL=https://api-int.rubinobs.dev/actions/contact-form/send \
--build-arg NEXT_PUBLIC_PLAUSIBLE_DOMAIN= \
--build-arg NEXT_PREVIEW_SLUG=preview-in-craft-cms \
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/prod-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
--build-arg NEXT_PUBLIC_DEBUG_LOGGING=false \
--build-arg CLOUD_ENV=PROD \
--build-arg NEXT_PUBLIC_GOOGLE_APP_ID=596747551410-vcqlrp7erg5c5gm0dkvc0k21mgi0ilg0.apps.googleusercontent.com \
--build-arg GOOGLE_APP_SECRET=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 \
--build-arg NEXT_PUBLIC_CONTACT_FORM_POST_URL=https://api.rubinobs.org/actions/contact-form/send \
--build-arg NEXT_PUBLIC_PLAUSIBLE_DOMAIN=rubinobservatory.org,all.epo.sites \
--build-arg NEXT_PREVIEW_SLUG=preview-in-craft-cms \
Expand Down
52 changes: 52 additions & 0 deletions components/atomic/Button/patterns/GoogleSSOButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import PropTypes from "prop-types";
import { useGoogleLogin } from "@react-oauth/google";
import { useRouter } from "next/router";
import { useAuthenticationContext } from "@/contexts/Authentication";
import SSOButton from "./SSOButton";

export default function GoogleSSOButton({ children, ...buttonProps }) {
const { authenticateWithGoogle } = useAuthenticationContext();
const { query, push, asPath, pathname } = useRouter();
const goToGoogleSignIn = useGoogleLogin({
state: asPath,
onSuccess: (response) => {
push(
{ pathname: asPath.split("?")[0], query: { sso: true } },
undefined,
{
shallow: true,
}
);
fetch("/api/authGoogle", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ code: response.code }),
})
.then((res) => res.json())
.then((data) => {
authenticateWithGoogle(data);
})
.catch(console.error);
},
onError: (error) => {
console.error(error);
},
flow: "auth-code",
});

return (
<SSOButton
{...buttonProps}
service="google"
type="button"
onClick={goToGoogleSignIn}
>
{children}
</SSOButton>
);
}

GoogleSSOButton.propTypes = {
children: PropTypes.node,
service: PropTypes.oneOf(["google", "facebook", "email"]),
};
1 change: 1 addition & 0 deletions components/atomic/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as SSOButton } from "./Button/patterns/SSOButton";
export { default as GoogleSSOButton } from "./Button/patterns/GoogleSSOButton";
export { default as EarlyAccess } from "./Flag/patterns/EarlyAccess";
export { default as Tile } from "./Tile";
export { default as InvestigationTile } from "./Tile/patterns/InvestigationTile";
Expand Down
3 changes: 2 additions & 1 deletion components/auth/AuthorizePage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const AUTHORIZED_TYPES = {
};

function isAuthorized(typeHandle, user, status) {
if (typeHandle === "educatorPages") return user?.group === "educators";
if (typeHandle === "educatorPages")
return user?.group === "educators" && status === "active";
if (typeHandle === "userProfilePage") return !!user && status === "active";
return false;
}
Expand Down
8 changes: 4 additions & 4 deletions components/modal/RegisterModal/JoinForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import Link from "next/link";
import { Link as BaseLink } from "@rubin-epo/epo-react-lib";
import { SSOButton } from "@/components/atomic";
import { GoogleSSOButton, SSOButton } from "@/components/atomic";
import useAuthModal from "@/hooks/useAuthModal";
import { useAuthenticationContext } from "@/contexts/Authentication";
import AuthModal from "../../AuthModal";
Expand All @@ -14,7 +14,7 @@ export default function JoinForm({ onEmailSignup }) {
const {
pendingGroup,
setPendingGroup,
goToGoogleSignIn,
// goToGoogleSignIn,
goToFacebookSignIn,
} = useAuthenticationContext();

Expand Down Expand Up @@ -47,9 +47,9 @@ export default function JoinForm({ onEmailSignup }) {
</AuthModal.Description> */}
</div>
<Styled.SSOButtons>
<SSOButton service="google" type="button" onClick={goToGoogleSignIn}>
<GoogleSSOButton service="google" type="button">
{t("join.continue_with_google")}
</SSOButton>
</GoogleSSOButton>
{/* <SSOButton
service="facebook"
type="button"
Expand Down
8 changes: 4 additions & 4 deletions components/modal/SignInModal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Link from "next/link";
import { useForm } from "react-hook-form";
import { useAuthenticationContext } from "@/contexts/Authentication";
import useAuthModal from "@/hooks/useAuthModal";
import { SSOButton } from "@/components/atomic";
import { GoogleSSOButton } from "@/components/atomic";
import {
Link as BaseLink,
Button,
Expand Down Expand Up @@ -118,9 +118,9 @@ export default function SignInModal() {
</Button>
</Styled.SignInAsButtons> */}
<Styled.SSOButtons>
<SSOButton service="google" onClick={goToGoogleSignIn}>
{t("sign_in.continue_with_google")}
</SSOButton>
<GoogleSSOButton service="google" type="button">
{t("join.continue_with_google")}
</GoogleSSOButton>
{/* <SSOButton service="facebook" onClick={goToFacebookSignIn}>
{t("sign_in.continue_with_facebook")}
</SSOButton> */}
Expand Down
22 changes: 1 addition & 21 deletions hooks/useAuthentication.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { useGoogleLogin } from "react-google-login";
import jwtDecode from "jwt-decode";
import {
authenticate,
Expand All @@ -17,7 +16,6 @@ import {
requestDeletion,
} from "@/lib/api/auth";

const GOOGLE_APP_ID = process.env.NEXT_PUBLIC_GOOGLE_APP_ID;
const SESSION_STORAGE_KEYS = [
"jwt",
"jwtExpiresAt",
Expand Down Expand Up @@ -83,24 +81,6 @@ export default function useAuthentication(data) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);

const { signIn: goToGoogleSignIn } = useGoogleLogin({
clientId: GOOGLE_APP_ID,
onSuccess: (response) => {
const ssoModalUrl = { pathname: "/", query: { sso: true } };
push(ssoModalUrl, undefined, {
shallow: true,
});
// eslint-disable-next-line no-console
console.log("onSuccess", response, "onSuccess");
authenticateWithGoogle({ idToken: response.tokenId });
},
onFailure: (error) => {
// eslint-disable-next-line no-console
console.log("onFailure", error, "onFailure");
console.error(error);
},
});

useEffect(() => {
// TODO: cancel promise if component unmounts first
(async () => await maybeRefreshToken())();
Expand Down Expand Up @@ -442,8 +422,8 @@ export default function useAuthentication(data) {
forgotPassword,
setPassword,
activateUser,
goToGoogleSignIn,
goToFacebookSignIn,
authenticateWithGoogle,
fetchUserData,
requestAccountDeletion,
};
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@
"@headlessui/react": "^1.6.6",
"@influxdata/influxdb-client": "^1.33.2",
"@popperjs/core": "^2.11.5",
"@react-oauth/google": "^0.12.1",
"@rubin-epo/epo-react-lib": "^1.2.9",
"add": "^2.0.6",
"classnames": "^2.3.1",
"convert": "^4.13.0",
"feed": "^4.2.2",
"focus-trap": "^7.0.0",
"focus-visible": "^5.1.0",
"google-auth-library": "^9.6.3",
"graphql": "^16.5.0",
"graphql-request": "^5.0.0",
"hoist-non-react-statics": "^3.3.2",
Expand All @@ -79,7 +81,6 @@
"npm-run-all": "^4.1.5",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-google-login": "^5.2.2",
"react-hook-form": "^7.33.1",
"react-i18next": "^12.0.0",
"react-is": "^18.2.0",
Expand Down
10 changes: 7 additions & 3 deletions pages/[[...uriSegments]].js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import PropTypes from "prop-types";
import { GoogleOAuthProvider } from "@react-oauth/google";
import { getGlobalData } from "@/api/global";
import { getAllEntries } from "@/api/entries";
import { getEntryDataByUri, getEntrySectionTypeByUri } from "@/api/entry";
Expand Down Expand Up @@ -57,6 +58,7 @@ function logNextDir() {
});
}

const GOOGLE_APP_ID = process.env.NEXT_PUBLIC_GOOGLE_APP_ID;
export default function Page({ section, globalData, ...entryProps }) {
globalData.localeInfo.locale === "es" ? updateI18n("es") : updateI18n("en");

Expand All @@ -75,9 +77,11 @@ export default function Page({ section, globalData, ...entryProps }) {
const Template = sectionMap[section] || PageTemplate;

return (
<GlobalDataProvider data={globalData}>
<Template {...entryProps} />
</GlobalDataProvider>
<GoogleOAuthProvider clientId={GOOGLE_APP_ID}>
<GlobalDataProvider data={globalData}>
<Template {...entryProps} />
</GlobalDataProvider>
</GoogleOAuthProvider>
);
}

Expand Down
26 changes: 26 additions & 0 deletions pages/api/authGoogle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { OAuth2Client } from "google-auth-library";

const GOOGLE_APP_ID = process.env.NEXT_PUBLIC_GOOGLE_APP_ID;
const GOOGLE_APP_SECRET = process.env.GOOGLE_APP_SECRET;

const oAuth2Client = new OAuth2Client(
GOOGLE_APP_ID,
GOOGLE_APP_SECRET,
"postmessage"
);

// exchanges Auth Code for Tokens
async function getTokens(code) {
const { tokens } = await oAuth2Client.getToken(code);

return tokens;
}

export default async function handler(req, res) {
try {
const { id_token: idToken } = await getTokens(req.body.code);
res.status(200).json({ idToken });
} catch (err) {
res.status(500).json({ error: "failed to load data" });
}
}
Loading
Loading