Access your Vue.js application using Google Sign-In (GIS)

Having trouble with the discontinuation of gapi.oauth2 by Google and finding the new Sign in With Google tools confusing.

Project Structure
Looking to implement user sign-in with Google on my Vue frontend and authenticate them using OIDC server flow on the backend.

My file structure is based on the default setup provided by Vue CLI.

Following the instructions in these docs, but struggling to understand how to initiate the sign-in process. How do we start the entire flow? I assumed it would be triggered by the new Sign in With Google Button, but unable to make the button work as intended.

This is my current approach:

In App.vue, I have the following code snippet

created() {
    loadGSIClient().then((this.GSILoaded = true));
}

googleAuth.js

export function loadGSIClient() {
  console.log("loading GSI");
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");
    script.src = "https://accounts.google.com/gsi/client";
    script.onload = () => {
      var client = window.google.accounts.oauth2.initCodeClient({
        client_id: process.env.VUE_APP_CLIENT_ID,
        scope: "https://www.googleapis.com/auth/calendar.readonly",
        ux_mode: "redirect",
        redirect_uri:
          "http://localhost:5001/sig-wig/us-central1/handleRedirect",
      });
      resolve(client);
    };
    script.onerror = (message, url, line, column, error) => {
      reject({ message, url, line, column, error });
    };
  });
}

Then, in my sign in file AccessRequest, I include

  created() {
    var google = window.google;
    google.accounts.id.initialize({
      client_id: process.env.VUE_APP_CLIENT_ID,
      callback: () => {
        "I'm a callback";
      },
    });
    google.accounts.id.renderButton(
      document.getElementById("buttonDiv"),
      { theme: "outline", size: "large" } // customization attributes
    );
  },

Encountering an error

Error in created hook: "TypeError: Cannot read properties of undefined (reading 'accounts')"
with this setup. It seems that window.google is available in App.vue but not in AccessRequest.vue. Is there a misunderstanding about how everything should function together?

Is the "Sign in With Google Button" designed to work with an OIDC Server flow?

Answer №1

Below is the Code Snippet
To begin, place the following code index.html in the public directory

<script src="https://accounts.google.com/gsi/client" async defer></script>
<template>
 <div ref="googleLoginBtn" />
</template>
<script>
  export default(){
    mounted() {
      const gClientId = [Your Client Id]
      window.google.accounts.id.initialize({
        client_id: gClientId,
        callback: this.handleCredentialResponse,
        auto_select: true
      })
      window.google.accounts.id.renderButton(
        this.$refs.googleLoginBtn, {
          text: 'signin_with', // or 'signup_with' | 'continue_with' | 'signin'
          size: 'large', // or 'small' | 'medium'
          width: '366', // max width 400
          theme: 'outline', // or 'filled_black' |  'filled_blue'
          logo_alignment: 'left' // or 'center'
        }
      )
    },
    methods: {
      async handleCredentialResponse(response) {
         console.log(response.credential)
         // Insert your server-side logic here
      }
    }
  }
</script>

Answer №2

In order to adhere to best practices, I suggest moving the logic outside of the index.html file. Below is an example of how this can be implemented:

Index.html

<script src="https://accounts.google.com/gsi/client"></script>
<script type="module">
  import { GOOGLE_USER_ID, handleCredentialResponse } from './src/utils/oauth_google.js';
  document.getElementById("g_id_onload").setAttribute("data-client_id", GOOGLE_USER_ID);
</script>
<div id="g_id_onload"
    data-callback="handleCredentialResponse"
    data-auto_prompt="false"
    >
</div>

Oauth_google.js

export const GOOGLE_USER_ID = import.meta.env.VITE_GOOGLE_USER_ID;


export function handleCredentialResponse(response) {
  const data = { token: response.credential };
  // Perform necessary actions
}

window.handleCredentialResponse = handleCredentialResponse;

.env

VITE_GOOGLE_USER_ID=YOUR_CREDENTIAL

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Instructions on how to trigger a function after adding HTML content to the directive

When working with the viewBannerCtrl controller and using the "customTable" directive, I encountered an issue. I am unable to access the "VBC.bannerAlert()" function from the directive even though I tried appending the code to the directive. Confusingly, I ...

Adding the children of JSON objects to every individual div element

How can I add each day's players [day-1, day-2, day-3, day-3] wrapped in a <span> into the .card-body section as required? The goal is to load only four card-body. var vehicles = { "day-1": { "player-1-1": "Ford", "player-1-2": "BMW ...

Utilizing Angular Forms for dynamic string validation with the *ngIf directive

I have a challenge where I need to hide forms in a list if they are empty. These forms contain string values. I attempted to use *ngIf but unfortunately, it did not work as expected and empty fields are still visible in the list. How can I address this iss ...

The state may be modified, but the component remains unchanged

I've been tasked with implementing a feature on a specific website. The website has a function for asynchronously retrieving data (tickets), and I need to add a sorting option. The sorting process occurs on the server side, and when a user clicks a s ...

Shut down the pop-up in Chrome before the DOM finishes loading

Utilizing the most recent iteration of the selenium web driver along with the Google Chrome browser, I am encountering an issue in my application. Following the click on the login button, a popup appears while the DOM is still loading. view image I simpl ...

Building a versatile login system for various roles and users using Vue.js

I am looking to develop a login page that caters to users with varying roles, such as customers and vendors. How should I go about creating this? ...

Hide multiple divs with similar ids in JQuery when clicking outside of them

Is there a way to hide all div elements with similar id if none of them are clicked on? Currently, my code only works for the first div because I am using index[0] to retrieve the id. How can I make it work for all ids? Below is the code snippet: $(win ...

How can I alter the icon's color?

Is it possible for the icon's color to change to red when the condition is greater than 0, and to gray when the condition is equal to zero? <TouchableOpacity onPress={() => { if (Object.values(selectedIt ...

Exploring AngularJS: Utilizing limitTo and filter

I'm having some trouble with using angular's limitTo and filter together. I want to search for a value in the search box, then apply a limit to the number of results displayed by entering a number in the filter box and clicking apply filter. Howe ...

Incorporate a Font Awesome button in front of the content of each list group item in Pug/Jade

I'm struggling to insert a Font Awesome icon before the list-group-item content within a Pug loop, but I can't seem to make it work. Adding the icon at the end of the list-group-item content is straightforward. How do I position it in front (I h ...

encountering a glitch while using console.log(util.format

Let me start by saying that I am fairly new to working with node.js. A friend of mine assisted me in writing the code snippet below. I have successfully installed the necessary packages search-google-geocode, csv-parser, fs, util, and async using npm. H ...

Validating data with Joi can result in multiple error messages being displayed for a single field

I'm attempting to implement a validation flow using the joi package, which can be found at https://www.npmjs.com/package/joi. 1) First, I want to check if the field category exists. If it doesn't, I should display the error message category requ ...

Utilizing Input Data from One Component in Another - Angular4

As a newcomer to Angular, I'm facing an issue where I need to access a variable from ComponentA in ComponentB. Here's the code snippet that demonstrates what I'm trying to achieve (I want to utilize the "favoriteSeason" input result in the " ...

Executing a jQuery code within a WordPress theme

I have been attempting to implement the following script within the header.php file of a Wordpress website: <script> jQuery(function($) { jQuery('[href=#membership]').attr( 'data-menu-top', '500' ); }); ...

Adjust the height of the container div for the carousel according to the length of the text displayed

My image carousel features description content positioned on the right for wide-screen windows. However, I want the description to shift below the images when the browser window reaches a certain breakpoint. The challenge I am facing is that the height of ...

How can TypeScript leverage the power of JavaScript libraries?

As a newcomer to TypeScript, I apologize if this question seems simplistic. My goal is to incorporate JavaScript libraries into a .ts file while utilizing node.js for running my program via the console. In my previous experience with JavaScript, I utilize ...

Having trouble with i18n types not functioning correctly in Typescript and Nuxt?

I am currently utilizing NuxtJS/i18n with TypeScript and have included its types in my TS config: { "compilerOptions": { "types": [ "@nuxt/types", "@nuxtjs/i18n", ] } } However, when attempti ...

Guide to running a NextJS app alongside an Express server backend on the same localhost port

I'm working on hosting my NextJS app, which is built with React, on the same localhost port as my express api-server backend. Within my express server API settings, I have configured my API server to listen on: http://localhost:3000/graphql How can ...

Smoothly scroll to the bottom of a dynamically updated div using native JavaScript

I am in the process of developing a chat application and my goal is to achieve a smooth scrolling animation that automatically moves the page down to the bottom of the div when dynamic messages are loaded. <ul id="messages"> <li ...

Unexpected disconnection from Socket.io server

Utilizing node.js service and angular client with socket.io for extended duration http requests. Service: export const socketArray: SocketIO.Socket[] = []; export let socketMapping: {[socketId: string]: number} = {}; const socketRegister: hapi.Plugin< ...