Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
August 17, 2021 10:10 pm GMT

Add the new Google Sign In to your React app!

TLDR: Scroll down and copy the code. You only need to add your login logic.

This article will cover:

  • A brief introduction to the new-ish Google Sign In api
  • How to implement it using React and Typescript
    • Add relevant typings on global window object

Intro

Google recently announced they are discontinuing their old auth-service "Google Sign-In" in favor for their new and improved service "Sign In With Google".

Their new service comes in two parts:

  1. Login button
  2. One Tap

You can read more about them here.
We'll cover the first one in this article, how it works and how to implement it in React with Typescript.

Compared to the old service, this one is much easier to use. It's straight-forward enough to implement the login button yourself without needing a library like (the awesome) react-google-login that's the go-to solution for the old api.

Google Auth Introduction

I'm just going to go over the basics here.

Disclaimer: There might be a much better way to do this. I would be happy to know how, so leave a comment! I couldn't find any examples of this, so I figured I'd post my implementation and hopefully help someone else.

Although the new auth api is a bit tricky to get your head around at first when using React, we can make it work. The trick is to understand how the script loads the client and how that fits with React's loading and rendering.

The google documentation covers both the html and javascript api, and we'll be using the latter. But since we're building with React, we mostly use the step-by-step guide to figure out how the auth api works. We have to account for how React loads and renders elements. Unfortunately this means we can't just statically just stick it in the header like the guide instructs.

After you followed the setup process, the documentation tells you to add a script tag to your header (in public/index.html), but since we're using React we're not going to do that. We're going to control when and where we run that script, and thus initiate the google auth client.

// The script that runs and load the new google auth client.// We're not(!) adding it to our header like the guide says.<script src="https://accounts.google.com/gsi/client" async defer></script>

Lets get started

First off, Typescript will complain about missing types on the window object. We'll fix that properly later.

What we'll implement first is adding the script that loads the google auth client when our sign-in page renders, add the "target div" that the script will be looking for, and initiate the client with our callback function.

The problem

Attaching that callback-function to the google client is what makes using the new auth api with React a bit troublesome. (but even more so using the old one!). If we add the script tag to the static html like the docs say, we can't pass it any function defined in react. We could maybe handle stuff by defining a function on the server-side of things, but I want to stay within React and handle this on the front-end and use my graphql-hooks to login.

The process

When our login page renders, we'll attach the google client-script to the header from inside a useEffect hook. We'll add an initializer-function to the onLoad-eventlistener for that script tag. The onLoad event will then trigger and initialize the google auth client with our callback attached.

The google client will then magically find our already rendered div with id=g_id_signin and render the login-button.

A nice looking, personalized google sign-in button should now be visible to the user.

alt text

The code

import { Button } from "@material-ui/core"import { useEffect, useState } from "react"export default function GoogleSignin() {  const [gsiScriptLoaded, setGsiScriptLoaded] = useState(false)  const [user, setUser] = useState(undefined)  useEffect(() => {    if (user?._id || gsiScriptLoaded) return    const initializeGsi = () => {      // Typescript will complain about window.google      // Add types to your `react-app-env.d.ts` or //@ts-ignore it.      if (!window.google || gsiScriptLoaded) return      setGsiScriptLoaded(true)      window.google.accounts.id.initialize({        client_id: GOOGLE_CLIENT_ID,        callback: handleGoogleSignIn,      })    }    const script = document.createElement("script")    script.src = "https://accounts.google.com/gsi/client"    script.onload = initializeGsi    script.async = true    script.id = "google-client-script"    document.querySelector("body")?.appendChild(script)    return () => {      // Cleanup function that runs when component unmounts      window.google?.accounts.id.cancel()      document.getElementById("google-client-script")?.remove()    }  }, [handleGoogleSignIn, initializeGsi, user?._id])const handleGoogleSignIn = (res: CredentialResponse) => {  if (!res.clientId || !res.credential) return    // Implement your login mutations and logic here.    // Set cookies, call your backend, etc.     setUser(val.data?.login.user)  })}return <Button className={"g_id_signin"} />}

You might want to add some more implementation details here and there. But this is the gist of it! You can at least use it as a starting point. Hope it helps!

Fixing the window types

If you're using create-react-app, you will already have the file react-app-env.d.ts in your project root. You can add the types for the google auth api there. I translated the api documentation to typescript types. There might be some errors since I haven't used and tested all the functions. But it should be correct.

/// <reference types="react-scripts" />interface IdConfiguration {  client_id: string  auto_select?: boolean  callback: (handleCredentialResponse: CredentialResponse) => void  login_uri?: string  native_callback?: Function  cancel_on_tap_outside?: boolean  prompt_parent_id?: string  nonce?: string  context?: string  state_cookie_domain?: string  ux_mode?: "popup" | "redirect"  allowed_parent_origin?: string | string[]  intermediate_iframe_close_callback?: Function}interface CredentialResponse {  credential?: string  select_by?:    | "auto"    | "user"    | "user_1tap"    | "user_2tap"    | "btn"    | "btn_confirm"    | "brn_add_session"    | "btn_confirm_add_session"  clientId?: string}interface GsiButtonConfiguration {  type: "standard" | "icon"  theme?: "outline" | "filled_blue" | "filled_black"  size?: "large" | "medium" | "small"  text?: "signin_with" | "signup_with" | "continue_with" | "signup_with"  shape?: "rectangular" | "pill" | "circle" | "square"  logo_alignment?: "left" | "center"  width?: string  local?: string}interface PromptMomentNotification {  isDisplayMoment: () => boolean  isDisplayed: () => boolean  isNotDisplayed: () => boolean  getNotDisplayedReason: () =>    | "browser_not_supported"    | "invalid_client"    | "missing_client_id"    | "opt_out_or_no_session"    | "secure_http_required"    | "suppressed_by_user"    | "unregistered_origin"    | "unknown_reason"  isSkippedMoment: () => boolean  getSkippedReason: () =>    | "auto_cancel"    | "user_cancel"    | "tap_outside"    | "issuing_failed"  isDismissedMoment: () => boolean  getDismissedReason: () =>    | "credential_returned"    | "cancel_called"    | "flow_restarted"  getMomentType: () => "display" | "skipped" | "dismissed"}interface Window {  google?: {    accounts: {      id: {        initialize: (input: IdConfiguration) => void        prompt: (          momentListener: (res: PromptMomentNotification) => void        ) => void        renderButton: (          parent: HTMLElement,          options: GsiButtonConfiguration,          clickHandler: Function        ) => void        disableAutoSelect: Function        storeCredential: Function<{          credentials: { id: string; password: string }          callback: Function        }>        cancel: () => void        onGoogleLibraryLoad: Function        revoke: Function<{          hint: string          callback: Function<{ successful: boolean; error: string }>        }>      }    }  }}

Shameless plug

If you like this kind of stuff and are looking for a job in Sweden, Gothenburg, hit me up!


Original Link: https://dev.to/mremanuel/add-the-new-google-sign-in-to-your-react-app-p6m

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To