Error calling gapi.client.oauth2.userinfo.get() getting profile information

156 Views Asked by At

I'm attempting to authenticate users with their google account using the implicit flow in order to retrieve that user's profile information, including:

  1. Email
  2. Phone number
  3. Organizational information (i.e. Company Name)
    const apiKey = 'XXXXXX';
    const clientId = 'XXXXXX';
    const scopes = 'profile';
    //const scopes = 'profile https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/user.phonenumbers.read';

    let client;
    let token;
    let peopleApiDiscovery;
    const discoveryDocs = ["https://people.googleapis.com/$discovery/rest?version=v1"];

    let tokenClient;
    let access_token;

    const gapiLoad = async () => {
        let clientResponse = await new Promise((resolve, error) => gapi.load('client', resolve));
        console.log(`Load gapi.`);
    }

    const gisInit = async () => {
        tokenClient = google.accounts.oauth2.initTokenClient({
            client_id: clientId,
            scope: scopes,
            callback: async (tokenResponse) => {
                console.log(`Token response:`, tokenResponse);
                access_token = tokenResponse.access_token;
                console.log(`Finished requesting access.`);

                loadApis();

                await loadUserInfo();
            },
        });
        console.log(`Loaded token client.`);
        await gapiLoad();
        await getToken();
    }

    gisInit();

    async function loadApis() {
        let loader = [];

        loader.push(gapi.client.load('https://www.googleapis.com/discovery/v1/apis/people/v1/rest'));

        await Promise.all(loader);

        console.log('Finished loading APIs.');
    }
    
    async function loadUserInfo() {
        console.log(`Loading user info.`);

        const response = gapi.client.oauth2.userinfo.get();
        console.log(`Loaded user info: `, response.json.toString());
    }

    async function getToken() {
        await tokenClient.requestAccessToken();
    }

Everything seems to work fine until the call to userinfo.get(). I receive the exception:

Error: arrayForEach was called with a non array value

It appears that there are parameters necessary for the get method, but I can't find any documentation of them.

Here are the associated script elements:

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

I've begun looking at trying to debug the obfuscated methods (which is difficult), but I get the sense that I may be doing something else wrong that I can't seem to find or figure out documentation for. Any assistance is appreciated.

1

There are 1 best solutions below

0
VonC On

In case this is coming from the response handling part of your code (as commented by EspressoCode, and since I do not see anything in google/google-api-javascript-client), try first to inspect the exact response you are receiving from the gapi.client.oauth2.userinfo.get() API call.
You might be getting an object instead of an array.

And update your loadUserInfo function to correctly handle potential errors and inspect the response structure. For instance, you can log the raw response to console before trying to access response.json.toString():

async function loadUserInfo() {
    console.log(`Loading user info.`);
    try {
        const response = await gapi.client.oauth2.userinfo.get();
        console.log(`Raw response: `, response);
        console.log(`Loaded user info: `, response.result);
    } catch (error) {
        console.error('Error fetching user info: ', error);
    }
}

You can also try and pass the parameters explicitly:

async function loadUserInfo() {
    console.log(`Loading user info.`);

    try {
        // Fetch user profile information
        const profileResponse = await gapi.client.people.people.get({
            'resourceName': 'people/me',
            'personFields': 'emailAddresses,names,organizations',
        });
        console.log('Profile response:', profileResponse);

        // Fetch user email
        const emailResponse = await gapi.client.people.people.get({
            'resourceName': 'people/me',
            'personFields': 'emailAddresses',
        });
        console.log('Email response:', emailResponse);

        // Add additional API calls to fetch other pieces of information as needed

    } catch (error) {
        console.error('Error fetching user info:', error);
    }
}

Make sure that the People API is loaded and initialized before making the above API calls, and that the necessary scopes are included in your OAuth 2.0 request to grant the necessary permissions.