Search code examples
node.jsaxiospassport.jsgoogle-people-apipassport-google-oauth2

Get phoneNumbers and adresses from google people Api Node JS Passport Google o Auth Strategy


I'm building a NPM package to simplify passport logins. At this time i'm implementing google o Auth 2 .0 Strategy and i want the function to login and register the user.

When the user Accepts the login and the scopes the idea is to gather some data extra besides the profile and email info. For instance want the birthday, gender phone numbers etc. So I've implemented a request using axios to the google People API. and I build the URL parsing the Google User ID and the access token granted by passport JS. But when I do that i can retrieve gender, birthday, organization but i dont get addresses or phone numbers.

I ll try to post the code in ordered fashion so its more readable. get route for the google auth with the scopes

router.get("/goa",passport.authenticate("google",{
scope:[
    "openid",
    "profile",
    "email",
    "https://www.googleapis.com/auth/contacts",
    "https://www.googleapis.com/auth/directory.readonly",
    "https://www.googleapis.com/auth/contacts.readonly",
    "https://www.googleapis.com/auth/user.birthday.read",
    "https://www.googleapis.com/auth/user.phonenumbers.read",
    "https://www.googleapis.com/auth/user.gender.read",
    "https://www.googleapis.com/auth/user.addresses.read"
]}))

Strategy definition Here the strategy have two choices justLogin or loginAndRegister the branch im working is the second one so ill provide the code of that function after the strategy definition The loginAndRegister function is the verify function for passport js

 function GoogleoAuth(authObject, loginOnly = false) {
    
            const { justLogin, loginAndregister } = oAuthModes(DAOgoa, DAOlocal, userNotFoundMessage);
            passport.use(new GoogleStrategy(Object.assign(Object.assign({}, authObject), { passReqToCallback: true, 
                scope: [
                    "openid",
                    "profile",
                    "email",
                    "https://www.googleapis.com/auth/contacts",
                    "https://www.googleapis.com/auth/user.birthday.read",
                    "https://www.googleapis.com/auth/user.phonenumbers.read",
                    "https://www.googleapis.com/auth/user.addresses.read",
                    "https://www.googleapis.com/auth/user.gender.read",
                    "https://www.googleapis.com/auth/user.organization.read",
                    "https://www.googleapis.com/auth/directory.readonly",
                    "https://www.googleapis.com/auth/contacts.readonly"

                ] }), (loginOnly) ? justLogin : loginAndregister));
            passport.serializeUser((user, done) => __awaiter(this, void 0, void 0, function* () {
                done(null, yield user._id);
            }));
            passport.deserializeUser((id, done) => {
                if (loginOnly) {
                    DAOlocal.findById(id, done);
                }
                else {
                    DAOgoa.findById(id, done);
                }
            });
            return this;
}

loginAndRegister verify function

const loginAndregister = (req, accessToken, _refreshToken, _profile, email, cb) => __awaiter(this, void 0, void 0, function* () {
        const authorizationObject = {
            "https://www.googleapis.com/auth/user.birthday.read": "birthdays",
            "https://www.googleapis.com/auth/user.phonenumbers.read": "phoneNumbers",
            "https://www.googleapis.com/auth/user.addresses.read": "addresses",
            "https://www.googleapis.com/auth/user.gender.read": "genders",
            "https://www.googleapis.com/auth/user.organization.read": "organizations",
            "openid": "",
            "https://www.googleapis.com/auth/userinfo.profile": "",
            "https://www.googleapis.com/auth/userinfo.email": "",
            "https://www.googleapis.com/auth/contacts":"",
            "https://www.googleapis.com/auth/contacts.readonly":"",
            "https://www.googleapis.com/auth/directory.readonly":""
        };
        let urlFields = "";
        const tokenInfo = yield axios_1.default.get(`https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=${accessToken}`);
        if ("data" in tokenInfo)
            if ("scope" in tokenInfo.data) {
                console.log("scopes exists");
                tokenInfo.data.scope.split(" ").forEach((scope) => {
                    if (authorizationObject[scope] !== "")
                        urlFields += authorizationObject[scope] + ",";
                });
                urlFields = urlFields.substring(0, urlFields.length);
            }
        console.log(urlFields);
        const extendedData = yield axios_1.default.get(`https://people.googleapis.com/v1/people/${email.id}?personFields=${urlFields}&access_token=${accessToken}`);
        console.log(extendedData.data, Object.keys(extendedData.data),accessToken);
        try {
            const resultado = yield DAOgoa.findByUserName(email.emails[0].value);
            loggerHLP_1.loggerObject.debug.debug({ level: "debug", method: "Login and Register GoogleoAuth", data: resultado });
            if (resultado) {
                return cb(null, resultado);
            }
            try {
                const usercreated = yield DAOgoa.createUser({ username: email.emails[0].value, password: email.id, name: email.name.givenName, lastname: email.name.familyName, avatar: email.photos[0].value });
                return cb(null, usercreated);
            }
            catch (err) {
                loggerHLP_1.loggerObject.error.error({ level: "error", method: "Login and Register GoogleoAuth", message: err });
                return cb(err, null, { message: "Error creating user" });
            }
        }
        catch (err) {
            loggerHLP_1.loggerObject.error.error({ level: "error", method: "Login and Register GoogleoAuth", message: err });
            return cb(err, null, { message: "Error login with oAuth" });
        }
    })

And in the google dev console ive this permissions set for my app:

.../auth/contacts   
.../auth/contacts.readonly  
.../auth/directory.readonly 
openid  
People API  .../auth/user.addresses.read    
People API  .../auth/user.birthday.read
People API  .../auth/user.phonenumbers.read
People API  .../auth/userinfo.email
People API  .../auth/userinfo.profile   

So I dont understand why it doesn't give me phone numbers and addresses but it gives me the rest of the resources i ask. At this time I'm only trying to get the thata to the

console.log(extendedData.data, Object.keys(extendedData.data),accessToken);

Solution

  • The API will only return phoneNumber and addresses if they were added in the user's profile under Contact info at https://aboutme.google.com, it will not return the data at https://myaccount.google.com/personal-info as that is considered "Recovery information".

    More context at https://issuetracker.google.com/issues/78151501