MomenSherif / react-oauth

Google OAuth2 using the new Google Identity Services SDK for React 🚀
https://www.npmjs.com/package/@react-oauth/google
MIT License
1.13k stars 141 forks source link

Request for GoogleOAuthProvider to work as a local component wrapper #328

Open Akitektuo opened 9 months ago

Akitektuo commented 9 months ago

Hello, We have a strange requirement for our React App to support multiple Client IDs, for this, we would need the GoogleOAuthProvider to work on individual components also. Right now, the package works only if GoogleOAuthProvider wraps the <App /> component.

To be more precise, I would like to set it on components that represent pages (for example the Login page) and that are loaded asynchronously as needed (accessed). To streamline our solution, we made the following HOC that just wraps the component with GoogleOAuthProvider, but without adding more JSX:

import { GoogleOAuthProvider } from "@react-oauth/google";
import React from "react";

export default function withGoogleProvider<T>(Component: React.FunctionComponent<T>, googleClientId: string) {
    const ComponentWithGoogleProvider = (props: T) => (
        <GoogleOAuthProvider clientId={googleClientId}>
            <Component {...props} />
        </GoogleOAuthProvider>
    );

    return ComponentWithGoogleProvider;
}

Which we can use in the following way for a component

const someClientId = "xxxxxxxxxxxxx";

const SomeClientLoginPage = () => {
  /// This makes use of inheritance to define the authorization flow for a specific client
  /// Also this is where *useGoogleLogin* is used and contains the logic for triggering the login
  useGoogleAuthenticationService(someClientAuthenticationService); 

  return null;
};

export default withGoogleProvider(SomeClientLoginPage, someClientId);

Would it be possible to achieve this? I took a peak at the source code and it seems as if this should work, but might be a small issue within the retrieval of context.

Please let me know if I can help with more information or possibly even more!

MomenSherif commented 9 months ago

Hey, GoogleOAuthProvider is just a react context, and doesn't need to be wrapped in the top level <App />, you must wrap the usage of GoogleButton or useGoogleLogin

so you can provider multiple GoogleOAuthProvider and your component will talk to the first parent that provider context value

Akitektuo commented 9 months ago

Hi, Thank you for your response, that's what I was expecting from the code, but instead of redirecting the user to the Google Page login just does nothing, removing any elements placed by us indicating that the application is loading. I can work on a sample to reproduce the issue if it helps so I can showcase the bug. Or do you know if someone else had this issue in the past and was just a misconfiguration on their part?

Below you can find how login is declared inside useGoogleAuthenticationService.

import { useLocation } from "react-router-dom";
import { GoogleAuthenticationService } from "../services/authentication/googleAuthenticationService";
import useGlobalState from "./useGlobalState";
import store from "../store";
import { useEffect, useMemo } from "react";
import { useGoogleLogin } from "@react-oauth/google";

const useGoogleAuthenticationService = (googleAuthenticationService: GoogleAuthenticationService) => {
    const { isAppLoading, hasError } = useGlobalState(store.auth);
    const { search } = useLocation();
    const code = useMemo(() => new URLSearchParams(search).get("code"), [search]);

    const login = useGoogleLogin({
        flow: "auth-code",
        scope: "openid email",
        ux_mode: "redirect",
        onError: console.error,
        onNonOAuthError: console.error
    });

    useEffect(() => {
        if (isAppLoading || hasError) return;

        if (code) {
            googleAuthenticationService.signIn(code);
        } else {
            login();
        }
    }, [isAppLoading, hasError, code, login]);
};

export default useGoogleAuthenticationService;
lauriinc commented 3 weeks ago

Did you ever figure this out? I've been struggling for days trying to create a portal using multiple Client IDs.