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

Is it possible to use a v-for loop within F7+Vue to dynamically update the title of each accordion item?

Is there a way to dynamically update the title of each accordion-item using a v-for loop in F7+Vue? I want the title of each accordion-item to match the Title property of the objects in my myList array that is being iterated through. Here is an example: ...

What is the best way to retrieve socket emitted data in a separate route in Express?

I'm currently working on a project that involves three specific files: index.html, result.html, and app.js. While I have successfully been able to emit data on button click and see it printed on the server, I am struggling to retrieve the value on res ...

Tips for showing a DialogBox when a blur event occurs and avoiding the re-firing of onBlur when using the DialogBox

Using React and Material UI: In the code snippet provided below, there is a table with TextFields in one of its columns. When a TextField triggers an onBlur/focusOut event, it calls the validateItem() method that sends a server request to validate the ite ...

Is there a way to dynamically expand and collapse all table rows, with the latest row always remaining visible, using pure JavaScript?

I have a form input field where I enter data. The entered data is then displayed in a table as a new row, with the most recent entry at the top. What I want to achieve is to show only the newest row in the table and hide all other rows. When I hover over ...

The Axios call functions properly within the Vue.js mounted() hook, however it encounters issues when placed inside

Here is an example that works well: mounted(soc=1) { const data = { society: soc } axios.get('/ajax/load-centers', { data }) .then(response => console.log(response.data)) } This function is called when a certain event is successf ...

Parsing HTML to access inner content

Currently, I have integrated an onClick event to an anchor tag. When the user interacts with it, my objective is to retrieve the inner HTML without relying on the id attribute. Below is the code snippet that illustrates my approach. Any assistance in acc ...

An easy way to adjust the date format when linking a date in ng-model with md-datepicker

<md-input-container> <label>Scheduled Date</label> <md-datepicker ng-model="editVersionCtrl.selectedPlannedDate" ng-change="editVersionCtrl.checkPlannedDate()"> </md-datepicker> </md-input-container> ...

Remove chosen tags from the options list in Material UI Autocomplete Multiple

When utilizing the Material UI Autocomplete for multiple values, the selected input is shown in the options list with a blue background color. Is there a way to configure the autocomplete to exclude already selected values from appearing in the options li ...

Print Vue page with the same styling as the original

How can I add a print button to my application that prints the page with the original CSS styles? I am currently using window.print() function and have a separate file called print.scss with specific print styles. @media print { header {display:none; ...

Error: Unable to locate module - The specified file cannot be resolved when utilizing an external JavaScript library

I am currently integrating a WYSIWYG editor (TUI Editor) into my Angular2+ application. Since there is no official Angular wrapper available, I have decided to create my own based on an existing wrapper. Due to some installation issues with npm, I saved t ...

The Material UI Drawer stays closed despite the state being set to true

Currently, I am in the process of developing a WebApp utilizing React and Material UI. Despite following numerous tutorials on implementing the Drawer component and poring over the documentation, I am still struggling to grasp its functionality. Even thou ...

Challenge arises when implementing conditional styling in Vuejs

I want to include a style that works in HTML: <div style="text-decoration: line-through"> Now I am attempting this in Vue.js 2: <div :style="{'text-decoration: line-through':true}"> However, the above code is not functioning corre ...

Importing an SVG file dynamically into a VueJS component

Is it feasible to achieve something similar to this in Vue.js? import '~/path/to/svg/${props_here}.svg'; I am interested in implementing this feature, could you please advise if it is doable in Vue.js? ...

What is causing the VueJS template ref to be undefined when dealing with multiple divs

I have been working on a simple Vue component and I am trying to access the DOM element from the template. The initial component works perfectly: <template> <div ref="cool">COOL!</div> </template> <script> export ...

What is the best way to interact with my component in React?

As a newcomer to Reactjs, I have a question regarding my current setup: The components in my project include navComponent.js, stackComponent.js, and nav.js I am trying to pass data from stackComponent.js to navComponent.js so that the nav.js data can be ...

Extracting the chosen content from a textarea using AngularJS

Greetings! I am currently experimenting with an example that involves displaying values in a text area. You can find the code on Plunker by following this link: Plunker Link <!DOCTYPE html> <html> <head> <script src="https://aj ...

Tips for unit testing an Angular Service that is primarily responsible for redirecting to an external page from the application

My service is responsible for redirecting to a separate login page since we are implementing login as a service. function redirectToMembership() { var returnURL = $location.host(); returnURL+="/#/Authorization"; $window.location.href=Environme ...

How can SQL data be loaded following the selection from a dropdown menu?

I have a pressing query that I need assistance with. I am aiming to achieve a certain task, but due to lack of prior experience in this area, I am unsure about how to proceed. My current situation involves populating a dropdown menu with names retrieved f ...

Tips on managing canvas overflow within a vuetify card and ensuring responsiveness

Seeks Responsive Design Solution for fabricjs Canvas Inside Vuetify Card Hello, I am currently struggling to implement a responsive fabricjs canvas inside vuetify and ensure that it adjusts properly on all screen sizes. Right now, the canvas is overflowin ...

The proper way to define an event delegator's syntax

Typically, when you want to handle a button click event, you would do so like this: $(document).ready(function() { $("button").click(function() { doSomething(); }); }); However, in the scenario of an event delegator, you may need to respon ...