Adding social media login

Hi guys,
I am trying to build social media login with facebook, LinkedIn and google.
For now i am doing it with google . So, I followed a post and it just told me how to get secret key and and Client id . Then i figured out that i need to add these codes to Server’s main JS files.
ServiceConfiguration.configurations.remove({
service: “google”
});
ServiceConfiguration.configurations.insert({
service: “google”,
clientId: “xxxxxxxxxxxxxxxxxxxxxxx”,
secret: “xxxxxxxxxxxxxxxxxxxxxxxx”,
});
Now i am stuck with the google login method. I don’t know how to proceed and get info on my collection. Accounts -google package gets user information to users package. So i twisted the methods a bit and applied a logic.

I am also not able to logout through google system and once i login for first time through this login system, i login successfully after getting in, if i log out i am unable to log out from the google login. After login out from my app, when i press the google login button again, it just gets in without asking to login. tried Meteor.logout(). Didn’t worked for me.
I am using fully customized login signup with blaze as front end.
Can someone guide me through…?

Just want to make sure you read the Meteor Guide on oauth login as this explains in detail what you need to do.

Also, it would help if you enclosed your code in 3 backticks so it is formatted correctly and more readable. This is a code snippet of the function we call on Google login button click in our React front-end code. There is some extra code in the error handling section as we also have a user invite system and we also limit the login to an actual paid Google G-Suite account and not just a Gmail account, but this should give you the general idea.

const errors = {
  'no-hd': 'This Google account is not a G Suite account, please try another account or contact support@clozer.ai',
  'duplicated-email': `Can't create an account because the email is already in use, please try another account or contact support@clozer.ai`,
  default: 'An error occurred while attempting to log in, please contact support@clozer.ai or try again later'
};

const onLoginWithGoogle = ({token, isLogIn}) => {
  const {scope} = ServiceConfiguration.configurations.findOne({service: 'google'});

  Meteor.loginWithGoogle(
    {requestPermissions: scope, requestOfflineToken: true, loginUrlParameters: {hd: '*'}},
    error => {
      if (error) {
        if (error.errorType === 'Accounts.LoginCancelledError') return;
        const message = errors[error.error] || errors.default;
        alert('Login error', message);
      } else if (token && !isLogIn) {
        acceptInviteMethod.call({token});
      }
    }
  );
};
1 Like

Another thing to think about if you don’t want duplicate accounts for users when they sign in with different oauth systems is how to merge the accounts on login. There are some packages for this you can Google, but we wrote our own account merge code to prevent this.

1 Like

Thanks a lot for your reply. I was stuck there for two days and now i am done with facebook and google logins( Somehow ) . But i don’t have any idea about LinkedIn login. Not too many people are using LinkedIn to login. that may be cause of shortage of good packages. For some reason, Accounts package don’t give any documentation. How they suppose new people to get there methods of calling Apis and their Syntax ? Meteor documentation is also not good enough for any beginners ( Or may be its just me : ) ). have any idea how do i go with LinkedIn ?

There’s a number of atmosphere packages for LinkedIn Oauth.

@skirunman Thanks for the example. I’m looking to add an invite system to my app where admins will invite users to provide access. A user will be able to either use an email / password or their Google account to sign up / log in.

In your code, it looks like you’re intercepting the loginWithGoogle function, checking for an invite token, and then doing something with that token.

A few questions:

  1. Did you create an Invitations collection where you’re setting an invite as accepted?
  2. How did you go about sending the invitation email? Did you use Meteor.sendEnrollmentEmail or roll your own email?
  3. How did you handle log ins / sign ups with Google when there is no token because:
    a) it’s a brand new account so the user is signing up and will subsequently invite others
    b) the invitation has been redeemed
  1. Did you create an Invitations collection where you’re setting an invite as accepted?

Yes, we track if invitation is accepted as well as allow admin to resend the invite.

  1. How did you go about sending the invitation email? Did you use Meteor.sendEnrollmentEmail or roll your own email?

Rolled our own using our email sending service like SendGrid, Mandrill, etc.

  1. How did you handle log ins / sign ups with Google when there is no token because:
    a) it’s a brand new account so the user is signing up and will subsequently invite others
    b) the invitation has been redeemed

We wrote custom code to handle all the situations like above and many others such as if an invited user already had an account, etc. Way to complex to explain here and unique to our particular use case. We also handle merging accounts from 3 different oauth sources. Our onCreateUser function calls multiple functions and has over 500 LOC to handle all these scenarios.

2 Likes

To give you some more insight, here is our schema definition for invites. We use NPM version of Simple Schema. auditSchema includes fields for who/when last updated the object, created object, deleted object, etc.

import SimpleSchema from 'simpl-schema';

import {auditSchema} from '/imports/api/lib/schema';

/**
 * Invite base schema for add forms
 * @type SimpleSchema
 */
export const inviteFormSchema = new SimpleSchema({
  email: {
    type: String,
    regEx: SimpleSchema.RegEx.Email
  },
  subject: {
    type: String
  },
  body: {
    type: String
  },
  inviteToOrg: {
    type: Boolean,
    optional: true
  }
});

/**
 * Invite base schema
 * @type SimpleSchema
 */
export const inviteSchema = new SimpleSchema({
  accepted: {
    type: Boolean
  },
  acceptedUserId: {
    type: String,
    optional: true
  },
  acceptedDate: {
    type: Date,
    optional: true
  },
  invitingUserId: {
    type: String
  },
  invitingUserOrgId: {
    type: String
  },
  accountCreated: {
    type: Boolean,
    autoValue() {
      if (this.isInsert) {
        return false;
      }
      return this.value;
    }
  },
  resendCount: {
    type: Number,
    autoValue() {
      if (this.isInsert) {
        return 0;
      }
      return this.value;
    }
  },
  sendDate: {
    type: Date,
    optional: true
  },
  token: {
    type: String
  }
});

inviteSchema.extend(inviteFormSchema);
inviteSchema.extend(auditSchema);