Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Google One Tap in Angular

I'd like to use Google One Tap in my Angular 11 app. Following the documentation I added <script async defer src="https://accounts.google.com/gsi/client"></script> to my html and then used the following code in my app.component.html:

<div id="g_id_onload"
    data-client_id="MY_GOOGLE_CLIENT_ID"
    data-callback="handleCredentialResponse",
    data-cancel_on_tap_outside="false">
</div>

The popup works fine, though I can't seem to log in. If I create a function handleCredentialResponse in app.component.ts, I get the following error: [GSI_LOGGER]: The value of 'callback' is not a function. Configuration ignored.

If I instead try to use the JavaScript API, Typescript throws the following error: Property 'accounts' does not exist on type 'typeof google'

What should I do to be able to using Google One Tap in Angular?

like image 554
Milan Ferus-Comelo Avatar asked Aug 01 '26 03:08

Milan Ferus-Comelo


1 Answers

I had a similar problem when I used the HTML API approach, so I ended up using the JavaScript API instead.

Here's what I did:

First, make sure to install the @types/google-one-tap package.

As you mentioned, I'm also importing the script in my index.html file, like so:

<body>
  <script src="https://accounts.google.com/gsi/client" async defer></script>
  <app-root></app-root>
</body>

Now, moving on to your main component which in my case is app.component.ts, import the following first:

import { CredentialResponse, PromptMomentNotification } from 'google-one-tap';

Then, you can add this on the ngOnInit(). Make sure to read the documentation to get more details on the onGoogleLibraryLoad event:

// @ts-ignore
window.onGoogleLibraryLoad = () => {
  console.log('Google\'s One-tap sign in script loaded!');

  // @ts-ignore
  google.accounts.id.initialize({
    // Ref: https://developers.google.com/identity/gsi/web/reference/js-reference#IdConfiguration
    client_id: 'XXXXXXXX',
    callback: this.handleCredentialResponse.bind(this), // Whatever function you want to trigger...
    auto_select: true,
    cancel_on_tap_outside: false
  });

  // OPTIONAL: In my case I want to redirect the user to an specific path.
  // @ts-ignore
  google.accounts.id.prompt((notification: PromptMomentNotification) => {
    console.log('Google prompt event triggered...');

    if (notification.getDismissedReason() === 'credential_returned') {
      this.ngZone.run(() => {
        this.router.navigate(['myapp/somewhere'], { replaceUrl: true });
        console.log('Welcome back!');
      });
    }
  });
};

Then, the handleCredentialResponse function is where you handle the actual response with the user's credential. In my case, I wanted to decode it first. Check this out to get more details on how the credential looks once it has been decoded: https://developers.google.com/identity/gsi/web/reference/js-reference#credential

handleCredentialResponse(response: CredentialResponse) {
// Decoding  JWT token...
  let decodedToken: any | null = null;
  try {
    decodedToken = JSON.parse(atob(response?.credential.split('.')[1]));
  } catch (e) {
    console.error('Error while trying to decode token', e);
  }
  console.log('decodedToken', decodedToken);
}
like image 198
maya.js Avatar answered Aug 02 '26 16:08

maya.js