Search code examples
javascriptoauthgoogle-signingoogle-one-tap

How to get OAuth token after Google One Tap sign in: JWT token response of one tap sign in to Google oAuth


I have been reading the documentation and so far no luck, require the OAuth Access token as well. however, the Google Identity service does not give back the oAuth Access token. instead, it returns a JWT token.

I'm looking for ways to use the JWT token response of one tap sign in to be passed in such a way that I can get back the oAuth Access token.

Link to documentation : Google One Tap Sign in

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

    window.onload = function () {
        google.accounts.id.initialize({
            client_id: 'myid.apps.googleusercontent.com',
            callback: handleCredentialResponse
        });
        google.accounts.id.prompt();
    }

</script>

<script>
    function parseJwt(token) {
        var base64Url = token.split('.')[1];
        var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
        var jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
        }).join(''));

        return JSON.parse(jsonPayload);
    };

    function handleCredentialResponse(response) {
        console.log(response);
        const responsePayload = parseJwt(response.credential);
        console.log(responsePayload);
    }
</script>

Solution

  • @user872176 this is how I solved the problem

    We can use identity service for signing the user in and use the user email as hint for the oAUth flow.

    In my previous comment I have created a form and requested the access token but we can use the google identity service to ask the user for oAuth to the app. with hint from the one tap sign in.

    Opening one tap sign in prompt

    function oneTapSignInPrompt() {
      google.accounts.id.initialize({
        client_id: '#',
        callback: handleCredentialResponse,
        cancel_on_tap_outside: false,
        itp_support: true,
      });
      google.accounts.id.prompt();
    }
    

    Handling response from One Tap

    function handleCredentialResponse(response) {
      // One Tap Sign in returns a JWT token.
      const responsePayload = parseJwt(response.credential);
      if (!responsePayload.email_verified) {
        showInvalidEmailToast();
        oneTapSignInPrompt();
      } else {
        // We are passing the signed in email id to oAuth.
        // If we pass an email id to oAuth consent.
        // If the user has already given the oAuth consent. it will get auto selected.
        oauthSignIn(responsePayload.email);
      }
    }
    

    Parsing JWT

    function parseJwt(token) {
      var base64Url = token.split('.')[1];
      var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
      var jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
      }).join(''));
      return JSON.parse(jsonPayload);
    };
    

    oAuth Consent

        // This method request the oauth consent for the passed in google account.
    function oauthSignIn(googleId) {
      const client = google.accounts.oauth2.initTokenClient({
        client_id: '',
        scope: 'https://www.googleapis.com/auth/userinfo.profile',
        hint: googleId,
        prompt: '',// Specified as an empty string to auto select the account which we have already consented for use.
        callback: (tokenResponse) => {
        access_token = tokenResponse.access_token;
        onOneTapSignIn(access_token); // Reuse the token whichever way you want
        },
      });
      client.requestAccessToken();
    }