Skip to content

Commit

Permalink
[F] Google OAuth lib parity with investigations-client
Browse files Browse the repository at this point in the history
AS close to same as can be without migrating from /pages to /app
  • Loading branch information
Blake Mason committed Feb 27, 2024
1 parent a2b7ec6 commit 4f7f21f
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 49 deletions.
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
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
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
28 changes: 28 additions & 0 deletions pages/api/authGoogle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
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);
// eslint-disable-next-line no-console
console.log("authGoogle token", idToken);
res.status(200).json({ idToken });
} catch (err) {
res.status(500).json({ error: "failed to load data" });
}
}
Loading

0 comments on commit 4f7f21f

Please sign in to comment.