1

I am creating open-source project using google drive api, but I have a issue!

how to create gapi-script authentication using next-auth on nextjs project?

I can make authentication in gapi-script with out next-auth, also can make using next-auth using googleProvider.

But how to make authendication using gapi-script npm package with next-auth?

gapi-script auth


    const initClient = () => {
    setIsLoadingGoogleDriveApi(true);
    gapi.client
      .init({
        apiKey: API_KEY,
        clientId: CLIENT_ID,
        discoveryDocs: DISCOVERY_DOCS,
        scope: SCOPES,
      })
      .then(
        function () {
          // Listen for sign-in state changes.
          gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);

          // Handle the initial sign-in state.
          updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
        },
        function (error) {}
      );
  };

* Click to See the Full Code using gapi-cript

Jackson Kasi
  • 119
  • 2
  • 7
  • 1
    Thank you for asking this question - I have a similar one! I started by using next-auth to log the user into google with the required scopes and getting hold of my user's access token. Now how i'm trying to figure out how to use that token to access gapi APIs – fotoflo Jul 20 '22 at 11:53
  • thanks for idea. if you find the solution, please share with me. Maybe if I find a solution to this, I'll be sure to let you know. – Jackson Kasi Jul 20 '22 at 14:25
  • hello @fotoflo you can fine something from here, https://blog.srij.dev/nextauth-google-access-token – Jackson Kasi Jul 20 '22 at 17:52

1 Answers1

1

I solved a similar problem by creating a Gapi Context and passing the user's token into the context.

I had previously grabbed the users token during next auth and stored it in my DB

import React, { useState, createContext, useEffect, useCallback } from "react";

export const GapiClientContext = createContext();

const GAPI_CONFIG = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_CONFIG_apiKey,
  clientId: process.env.GOOGLE_ID,
  scope: "https://www.googleapis.com/auth/gmail.send",
  discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"],
  fetch_basic_profile: true,
  immediate: true,
  plugin_name: "app name",
};


const GapiContextProvider = ({ session, ...props }) => {

  const [GapiClient, setGapiClient] = useState(); //{ gapi });

  // to test initClient properly, remove access from third party access after each grant:
  // https://myaccount.google.com/permissions?continue=https%3A%2F%2Fmyaccount.google.com%2Fsecurity%3Fpli%3D1
  // then logout
  // to ensure gapi only loads once: https://stackoverflow.com/questions/68985492/how-to-prevent-script-from-loading-multiple-times-with-react

  const initClient = useCallback(async () => {
    if (window.gapiIsInitialized) return;

    console.log("intting gapi");
    return gapi.client.init(GAPI_CONFIG).then(
      () => {
        const access_token =
          session.externalAccounts.find((acct) => acct.provider === "gmail")
            ?.access_token ?? "";

        if (access_token === "") return;

        gapi.client.setToken({ access_token });

        window.gapiIsInitialized = true;
        setGmailIsDisabled(false);
        return;
      },
      (e) => {
        window.gapiIsLoading = false;
        console.info("error init gapi client", e.details);
      }
    );
  }, []);

  const setupGapi = useCallback(async () => {
    const gapi = await import("gapi-script").then((pack) => pack.gapi);
    // https://stackoverflow.com/questions/71040050/why-am-i-getting-syntaxerror-cannot-use-import-statement-outside-a-module
    setGapiClient({ gapi });

    try {
      await gapi.load("client:auth2", initClient);
    } catch (e) {
      window.gapiIsLoading = false;
      console.log("couldnt sign in to gAPI!", e);
    }
  }, [initClient]);

  useEffect(() => {
    if (window.gapiIsInitialized || window.gapiIsLoading) return;
    window.gapiIsLoading = true;
    setupGapi();
  }, [initClient, setupGapi]);

  return (
    <GapiClientContext.Provider
      value={{
        GapiClient
      }}
    >
      {props.children}
    </GapiClientContext.Provider>
  );
};

export default GapiContextProvider;

Then in my application I wrapped the consuming components A full example would show that I also tracked the state of sending email from within the context provider... you can see that here:

https://github.com/fotoflo/next-firebase-multi-auth-starter

... i'll be merging this context in in the next couple days also

          <GapiContextProvider session={session}>
            <SendGmailButton emailMessage={emailMessage} />
          </GapiContextProvider>

Hope this is helpful! Good luck :-)

fotoflo
  • 821
  • 1
  • 9
  • 21