title: How to get profile information from Google Identity Services?
body: <p>I am using the GAPI async/await example from <a href="https://developers.google.com/identity/oauth2/web/guides/migration-to-gis#gapi-asyncawait" rel="nofollow noreferrer">https://developers.google.com/identity/oauth2/web/guides/migration-to-gis#gapi-asyncawait</a></p>
  <p>I'm having difficulty figuring out how to get information about the user.  I want to get the user's name and email.</p>
  <p>I believe the preferred solution is to get the user's info from id_token.  I have added the scopes &quot;profile email openid&quot;, but I am still not getting an id_token returned.</p>
  <p>I also tried loading a gapi client for &quot;oauth2&quot; and &quot;plus&quot; to query the profile info but was also unsuccessful with that.</p>
  <p>This is my current code:</p>
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;&lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;GAPI with GIS async/await&lt;/h1&gt;
    &lt;button id=&quot;showEventsBtn&quot; onclick=&quot;showEvents();&quot;&gt;Show Calendar&lt;/button&gt;&lt;br&gt;&lt;br&gt;
    &lt;button id=&quot;revokeBtn&quot; onclick=&quot;revokeToken();&quot;&gt;Revoke access token&lt;/button&gt;
  
    &lt;script&gt;
  
      const gapiLoadPromise = new Promise((resolve, reject) =&gt; {
        gapiLoadOkay = resolve;
        gapiLoadFail = reject;
      });
      const gisLoadPromise = new Promise((resolve, reject) =&gt; {
        gisLoadOkay = resolve;
        gisLoadFail = reject;
      });
  
      var tokenClient;
  
      (async () =&gt; {
        document.getElementById(&quot;showEventsBtn&quot;).style.visibility = &quot;hidden&quot;;
        document.getElementById(&quot;revokeBtn&quot;).style.visibility = &quot;hidden&quot;;
  
        // First, load and initialize the gapi.client
        await gapiLoadPromise;
        await new Promise((resolve, reject) =&gt; {
          // NOTE: the 'auth2' module is no longer loaded.
          gapi.load('client', { callback: resolve, onerror: reject });
        });
        await gapi.client.init({
          // NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
        })
          .then(function () {  // Load the Calendar API discovery document.
            gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
            gapi.client.load('https://www.googleapis.com/discovery/v1/apis/people/v1/rest');
            gapi.client.load('https://www.googleapis.com/discovery/v1/apis/plus/v1/rest');
            gapi.client.load('https://www.googleapis.com/discovery/v1/apis/oauth2/v1/rest');
          });
  
        // Now load the GIS client
        await gisLoadPromise;
        await new Promise((resolve, reject) =&gt; {
          try {
            tokenClient = google.accounts.oauth2.initTokenClient({
              client_id: 'YOUR_CLIENT_ID',
              scope: 'profile email openid https://www.googleapis.com/auth/calendar.readonly',
              prompt: 'consent',
              callback: '',  // defined at request time in await/promise scope.
            });
            resolve();
          } catch (err) {
            reject(err);
          }
        });
  
        document.getElementById(&quot;showEventsBtn&quot;).style.visibility = &quot;visible&quot;;
        document.getElementById(&quot;revokeBtn&quot;).style.visibility = &quot;visible&quot;;
      })();
  
      async function getToken(err) {
  
        if (err.result.error.code == 401 || (err.result.error.code == 403) &amp;&amp;
          (err.result.error.status == &quot;PERMISSION_DENIED&quot;)) {
  
          // The access token is missing, invalid, or expired, prompt for user consent to obtain one.
          await new Promise((resolve, reject) =&gt; {
            try {
              // Settle this promise in the response callback for requestAccessToken()
              tokenClient.callback = (resp) =&gt; {
                if (resp.error !== undefined) {
                  reject(resp);
                }
                // GIS has automatically updated gapi.client with the newly issued access token.
                console.log('gapi.client access token JSON: ' + JSON.stringify(gapi.client.getToken()));
                console.log(gapi.client.getToken());
                resolve(resp);
              };
              tokenClient.requestAccessToken();
            } catch (err) {
              console.log(err)
            }
          });
        } else {
          // Errors unrelated to authorization: server errors, exceeding quota, bad requests, and so on.
          throw new Error(err);
        }
      }
  
      function showEvents() {
  
        // Try to fetch a list of Calendar events. If a valid access token is needed,
        // prompt to obtain one and then retry the original request.
        gapi.client.calendar.events.list({ 'calendarId': 'primary' })
          .then(calendarAPIResponse =&gt; console.log(JSON.stringify(calendarAPIResponse)))
          .catch(err =&gt; getToken(err))  // for authorization errors obtain an access token
          .then(retry =&gt; gapi.client.calendar.events.list({ 'calendarId': 'primary' }))
          .then(calendarAPIResponse =&gt; console.log(JSON.stringify(calendarAPIResponse)))
          .catch(err =&gt; console.log(err));   // cancelled by user, timeout, etc.
      }
  
      function revokeToken() {
        let cred = gapi.client.getToken();
        if (cred !== null) {
          google.accounts.oauth2.revoke(cred.access_token, () =&gt; { console.log('Revoked: ' + cred.access_token) });
          gapi.client.setToken('');
        }
      }
  
    &lt;/script&gt;
  
    &lt;script async defer src=&quot;https://apis.google.com/js/api.js&quot; onload=&quot;gapiLoadOkay()&quot;
      onerror=&quot;gapiLoadFail(event)&quot;&gt;&lt;/script&gt;
    &lt;script async defer src=&quot;https://accounts.google.com/gsi/client&quot; onload=&quot;gisLoadOkay()&quot;
      onerror=&quot;gisLoadFail(event)&quot;&gt;&lt;/script&gt;
  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>