5

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>
Akash g krishnan
  • 469
  • 5
  • 16

3 Answers3

10

@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();
}
Akash g krishnan
  • 469
  • 5
  • 16
1

Currently Google Sign in Can not be used along with oAuth.

However you can have an implementation where you can open oAuth directly instead of One Tap sign in by using the following code in the window.onload. This will add the access Token to the redirect Url specified. which you can access using any of the vanilla js techniques.

function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

  // Create <form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement('form');
  form.setAttribute('method', 'GET'); // Send as a GET request.
  form.setAttribute('action', oauth2Endpoint);

  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {
    'client_id': '',
    'redirect_uri': 'http://localhost:3000',
    'response_type': 'token',
    'scope': 'https://www.googleapis.com/auth/userinfo.profile',
    'include_granted_scopes': 'true',
    'state': 'pass-through value'
  };

  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }
  document.body.appendChild(form);
  form.submit();
}
Akash g krishnan
  • 469
  • 5
  • 16
0

I think you cannot do it with "One tap", but you can do it with new Google Identity service. https://developers.google.com/identity/oauth2/web/guides/migration-to-gis#gis-only

user872176
  • 108
  • 1
  • 7