Help needed in User Accounts Creation

Hi,

I am working with Meteor User accounts to create users. I have implemented two ways of creating users.

  1. By using accounts-password to create (default one ).
  2. OAuth Services (accounts-google and accounts-facebook)

A user account generated with accounts-password have the document shown below

{
  "_id": "DQnDpEag2kPevSdJY",
  "createdAt": "2015-12-10T22:34:17.610Z",
  "services": {
    "password": {
      "bcrypt": "XXX"
    },
    "resume": {
      "loginTokens": [
        {
          "when": "2015-12-10T22:34:17.615Z",
          "hashedToken": "XXX"
        }
      ]
    }
  },
 -----
----
}

Where as a user account generated with accounts-google or account-facebook have the document shown below.

{
  "_id": "Ap85ac4r6Xe3paeAh",
  "createdAt": "2015-12-10T22:29:46.854Z",
  "services": {
    "facebook": {
      "accessToken": "XXX",
      "expiresAt": 1454970581716,
      "id": "XXX",
      "email": "myname@gmail.com",
      "name": "Ada Lovelace",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "link": "https://www.facebook.com/app_scoped_user_id/XXX/",
      "gender": "female",
      "locale": "en_US",
      "age_range": {
        "min": 21
      }
    },
---
---
---

Now the real issue is, Although the email address used is same for both accounts-password and accounts-google (in my case email is myname@gmail.com), two different user accounts are being created.

I am looking for solution Something like below. (Note: Services has both “Password” and “Facebook” sections under single account)

{
  "_id": "DQnDpEag2kPevSdJY",
  "createdAt": "2015-12-10T22:34:17.610Z",
  "services": {
    "password": {
      "bcrypt": "XXX"
    },
    "facebook": {
      "accessToken": "XXX",
      "expiresAt": 1454970581716,
      "id": "XXX",
      "email": "myname@gmail.com",
      "name": "Ada Lovelace",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "link": "https://www.facebook.com/app_scoped_user_id/XXX/",
      "gender": "female",
      "locale": "en_US",
      "age_range": {
        "min": 21
      }
    },
  },
 -----
----
}

Is there a way where only one account is being generated in both cases, means if a user is already existed and the same is trying with OAuth service, first account should be used to accommodate the service ?

1 Like

Unfortunately Nobody is able to help me out on the above issue, despite providing
enough details. After 3 days of long struggle, somehow managed to create solution for the above issue.

In imports/startup/server/accounts.js I have added the below validation logic which always validates the newly created account.

The idea is, this process checks if user is already existed in database. If the user exists, further checks if its created from accounts-password or accounts-google/facebook .

Based on the existing type modify the existing fields with new fields and throw an error with a fancy message (This actually prevents the new account to be created).

Accounts.validateNewUser(function (user) {

// first check what is the newly creating service
  var service =
    user.services.google || user.services.facebook || user.services.password;

  
  if (!service) return true;

  var existingUser = null;
// due to some issues both `Meteor.users.findOne(email)` as well `Account.findUserByEmail(email)` methods have been used to find the existing user status

  if (user.services.password) {
    var email = user.emails[0].address;
    existingUser = Meteor.users.findOne({
      $or: [
        { "registered_emails[0].address": email },
        { "services.google.email": email },
        { "services.facebook.email": email },
      ],
    });
     
  } else {
    var email = service.email;
    //console.log(" retrieved email ", email);
    existingUser = Accounts.findUserByEmail(email);
  }

  //console.log(" existingUser  : ", existingUser);
  if (!existingUser) return true;

  if (user.services.google) {
    Meteor.users.update(
      { _id: existingUser._id },
      {
        $set: {
          profile: user.profile,
          "services.google": user.services.google,
        },
        
      }
    );
  } else if (user.services.facebook) {
    Meteor.users.update(
      { _id: existingUser._id },
      {
        $set: {
          profile: user.profile,
          "services.facebook": user.services.facebook,
        },
        
      }
    );
  } else {
    Meteor.users.update(
      { _id: existingUser._id },
      {
        $set: {
          profile: user.profile,
          "services.password": user.services.password,
          "services.email": user.services.email,
          emails: user.emails,
        },
        
      }
    );
  }

  throw new Meteor.Error(
    205,
    "Merged with your existing Social Login accounts now. Try refresh the page and sign in again. That should work !!"
  );
});
2 Likes

Thanks for sharing your fix @syam22587

1 Like

Maybe coming really late, but there is a package for that:
https://github.com/Meteor-Community-Packages/meteor-link-accounts
Used it a few months ago and it looked functional and working.

1 Like