Skip to content

Instantly share code, notes, and snippets.

@jakekara
Created September 28, 2020 19:49
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakekara/652e3c3bf272cd682ae39b50f1c45062 to your computer and use it in GitHub Desktop.
Save jakekara/652e3c3bf272cd682ae39b50f1c45062 to your computer and use it in GitHub Desktop.
Authenticating with gapi in a react/typescript project

Authenticating with Google API in react/typescript project

This was surprisingly annoying to figure out.

I used this Google API documentation for vanilla JS, but it was a lot more trouble than I expected to get it working in a TypeScript React project.

Long story short, you need to install:

  • gapi-script
  • @types/gapi
  • types/gapi.auth2

For some architectural reason it seems the gapi npm package can't just be imported into the .tsx file.

import React, { ReactElement, useEffect, useState } from "react";
import { gapi } from "gapi-script";
import { config } from "dotenv";
config(); // I just don't like mixing import and require
const DISCOVERY_DOCS = [
"https://www.googleapis.com/discovery/v1/apis/drive/v3/rest",
"https://www.googleapis.com/discovery/v1/apis/people/v1/rest",
];
const SCOPES = "https://www.googleapis.com/auth/drive.metadata.readonly";
const API_KEY = process.env.REACT_APP_GAPI_API_KEY;
const CLIENT_ID = process.env.REACT_APP_GAPI_CLIENT_ID;
console.log("client_id", CLIENT_ID);
console.log("process.env", process.env);
let done = false;
const initClient = (options: {
updateLoggedInStatus: (status: boolean) => void;
}) => {
if (done) {
return;
}
done = true;
gapi.client
.init({
apiKey: API_KEY,
client_id: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES,
})
.then(() => {
// Listen for sign-in state changes.
console.log("gapi.auth2", gapi.auth2);
gapi.auth2
.getAuthInstance()
.isSignedIn.listen(options.updateLoggedInStatus);
// Handle the initial sign-in state.
options.updateLoggedInStatus(
gapi.auth2.getAuthInstance().isSignedIn.get()
);
})
.catch((err: any) => {
console.error("Caught error", err);
});
};
function LogInOutButton(options: {
loggedIn: boolean;
logIn: () => void;
logOut: () => void;
}): ReactElement {
const { loggedIn, logIn, logOut } = options;
const buttonText = loggedIn ? "Log out" : "Log in";
const buttonAction = loggedIn ? logOut : logIn;
return <button onClick={buttonAction}>{buttonText}</button>;
}
export function GDrive(): ReactElement {
const [loggedInStatus, setLoggedInStatus] = useState<boolean>(false);
const [initiatedClient, setInitiatedClient] = useState<boolean>(false);
useEffect(() => {
gapi.load("client:auth2", () =>
initClient({
updateLoggedInStatus: (status) => {
console.log("Login status", status);
setLoggedInStatus(status);
},
})
);
setInitiatedClient(true);
}, [initiatedClient]);
return (
<div>
<div>You are {loggedInStatus ? "" : "not"} signed in</div>
<LogInOutButton
loggedIn={loggedInStatus}
logIn={() => gapi.auth2.getAuthInstance().signIn()}
logOut={() => gapi.auth2.getAuthInstance().signOut()}
/>
</div>
);
}
@khan-skadi
Copy link

React can't find a declaration module for gapi-script, after i imported gapi in the component, and having installed those 3 packages that you have written.
Any solution for this ?

@jakekara
Copy link
Author

I think you're correct and I had to add a .d.ts file containing:

declare module "gapi-script";

I don't have time to test it out now but if that works for you, would you let me know?

Best of luck.

@khan-skadi
Copy link

This doesn't work.
node-modules is not committed on github, so it will only work on my machine. And if you have setup github actions, it wont compile for the same reason - the package is only locally updated.
Do you know of any other workaround ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment