When should I use linkCredentials?

Hi ! I’m having trouble understanding when to use the linkCredentials method.

I am using both the Email/Password and the Google authentication methods provided by the Realm API. Since the Google sign in/log in uses the same .logIn() method to both create a new user and log in an existing user, a problem arises in the following case: if my user already has signed up using Email/Password and he/she later tries to log in with Google (by mistake, let’s say), Realm doesn’t detect that the email is already used and it creates a new account.

The obvious solution to my problem would be to use the linkCredentials method but when am I supposed to use it? In the scenario I described, when my user tries to log in with Google, I only get access to the user object inside the .then() part of the .logIn() promise, and at this point a duplicate user has already been created - this post indicates that it is impossible to link two existing users linkCredentials with an existing Google user

I created a function which combined with a webhook allows me to check whether the email is already used, but - same issue - I don’t see where I could add this check in the Google auth flow as the .then() part of the logIn() method is called when the user selects the account in the list of Google accounts, leaving me no moment when I do know the email address of the Google account in order to check if it is already used before the duplicate user is added.

This is really problematic and I would appreciate any hints/ideas on the topic.

Many thanks,

Benjamin

Hi Benjamin, welcome to the community forum!

I’ve no experience with linkCredentials, but this is how I’d avoid the issue of duplicate users.

I’d have a User collection that contains a document for each registered user (chances are that you’ll want to store some extra data for each user anyway). You can optionally link the User collection to the Realm user through custom data (in which case, the user token contains a snapshot of that custom data – refreshed every time the user logs in).

You can auto-populate the User collection by setting up a Realm trigger that executes when a new user is registered:

This is the code from that trigger:

exports = function({user}) {
  const db = context.services.get("mongodb-atlas").db("RChat");
  const userCollection = db.collection("User");
  
  const partition = `user=${user.id}`;
  const defaultLocation = context.values.get("defaultLocation");
  const userPreferences = {
    displayName: ""
  };
  
  console.log(`user: ${JSON.stringify(user)}`);
  
  const userDoc = {
    _id: user.id,
    partition: partition,
    userName: user.data.email,
    userPreferences: userPreferences,
    location: context.values.get("defaultLocation"),
    lastSeenAt: null,
    presence:"Off-Line",
    conversations: []
  };
  
  return userCollection.insertOne(userDoc)
  .then(result => {
    console.log(`Added User document with _id: ${result.insertedId}`);
  }, error => {
    console.log(`Failed to insert User document: ${error}`);
  });
};

You could then have a simple Realm function (that can run as the system user) to check whether a User document already exists for a given email address. This function can be called from your app if it’s logged in anonymously.

This article describe a chat app I built that uses option 1. It describes the data architecture used and includes a link to the repo containing both the iOS (SwiftUI) and Realm apps.

1 Like

Hi Andrew,

Your approach certainly restricts duplicate user (having same email id) creation but it will pose a bumpy user experience. If user already logged in with one identity, he/she cannot login with other identity - i.e., once logged with email/password, you cannot login with Google or Facebook.

There should be a mechanism (obviously at server-side) to link/merge identities based on email address. This practice is being followed by many other apps like Udemy, Myntra etc.