From 19fcd711ff01374aa0b7d37a595dd6b03a233db4 Mon Sep 17 00:00:00 2001 From: Dennis Chen <41879777+chennisden@users.noreply.github.com> Date: Tue, 13 Aug 2024 10:00:24 -0700 Subject: [PATCH] Add Google OAuth (#289) Also update CONTRIBUTING.md to reflect adjusted Vite env var --- CONTRIBUTING.md | 3 +- frontend/package-lock.json | 11 +++ frontend/package.json | 1 + frontend/src/components/auth/AuthProvider.tsx | 77 +++++++++++++++---- frontend/src/constants/env.ts | 1 + frontend/src/gen/api.ts | 66 +++++++++++++++- frontend/src/vite-env.d.ts | 1 + store/app/crud/users.py | 6 +- store/app/routers/auth/google.py | 50 ++++++++++++ store/app/routers/users.py | 6 +- store/app/utils/email.py | 2 +- tests/test_listings.py | 2 +- 12 files changed, 201 insertions(+), 25 deletions(-) create mode 100644 store/app/routers/auth/google.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f86b3cf6..9b56349d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,8 +129,7 @@ export GITHUB_CLIENT_ID='' export GITHUB_CLIENT_SECRET='' # For Google OAuth -export GOOGLE_CLIENT_ID='' -export GOOGLE_CLIENT_SECRET='' +export VITE_GOOGLE_CLIENT_ID='' ``` ### Github OAuth Configuration diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 14ea7609..d8f2ecd5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,6 +11,7 @@ "@formspree/react": "^2.5.1", "@hookform/resolvers": "^3.9.0", "@radix-ui/react-slot": "^1.1.0", + "@react-oauth/google": "^0.12.1", "@react-three/drei": "^9.109.2", "@react-three/fiber": "^8.16.8", "@uidotdev/usehooks": "^2.4.1", @@ -2534,6 +2535,16 @@ "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", "license": "MIT" }, + "node_modules/@react-oauth/google": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.12.1.tgz", + "integrity": "sha512-qagsy22t+7UdkYAiT5ZhfM4StXi9PPNvw0zuwNmabrWyMKddczMtBIOARflbaIj+wHiQjnMAsZmzsUYuXeyoSg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@react-spring/animated": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.6.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 028900e3..09ada1a6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,6 +26,7 @@ "@formspree/react": "^2.5.1", "@hookform/resolvers": "^3.9.0", "@radix-ui/react-slot": "^1.1.0", + "@react-oauth/google": "^0.12.1", "@react-three/drei": "^9.109.2", "@react-three/fiber": "^8.16.8", "@uidotdev/usehooks": "^2.4.1", diff --git a/frontend/src/components/auth/AuthProvider.tsx b/frontend/src/components/auth/AuthProvider.tsx index 1161e63b..f9f74c2b 100644 --- a/frontend/src/components/auth/AuthProvider.tsx +++ b/frontend/src/components/auth/AuthProvider.tsx @@ -1,19 +1,75 @@ +import { useEffect, useState } from "react"; import { FaGithub } from "react-icons/fa"; import { FcGoogle } from "react-icons/fc"; +import { GoogleOAuthProvider, useGoogleLogin } from "@react-oauth/google"; +import { GOOGLE_CLIENT_ID } from "constants/env"; +import { useAlertQueue } from "hooks/useAlertQueue"; +import { useAuthentication } from "hooks/useAuth"; + import { Button } from "components/ui/Button/Button"; interface AuthProvider { - handleGoogleSubmit?: () => void; + handleGoogleSubmit?: ( + event: React.MouseEvent, + ) => Promise; handleGithubSubmit?: ( event: React.MouseEvent, ) => Promise; } -const AuthProvider = ({ - handleGoogleSubmit, - handleGithubSubmit, -}: AuthProvider) => { +const GoogleAuthComponentInner = () => { + const [credential, setCredential] = useState(null); + const auth = useAuthentication(); + const { addErrorAlert } = useAlertQueue(); + + useEffect(() => { + (async () => { + if (credential !== null) { + const { data, error } = await auth.client.POST("/users/google/login", { + body: { + token: credential, + }, + }); + if (error) { + addErrorAlert(error); + } else { + auth.login(data.api_key); + } + } + })(); + }, [credential]); + + const login = useGoogleLogin({ + onSuccess: (tokenResponse) => { + const returnedCredential = tokenResponse.access_token; + if (returnedCredential === undefined) { + addErrorAlert("Failed to login using Google OAuth."); + } else { + setCredential(returnedCredential); + } + }, + onError: () => { + addErrorAlert("Failed to login using Google OAuth."); + }, + onNonOAuthError: () => { + addErrorAlert("Failed to login using Google OAuth."); + }, + }); + + return ( + + ); +}; + +const AuthProvider = ({ handleGithubSubmit }: AuthProvider) => { return (
@@ -23,14 +79,9 @@ const AuthProvider = ({
{/* Google */} - + + + {/* Github */}