Account linking through actions [Critical issue]

Posting this as a separate topic as the comment did not get any response.

I marked this one as critical because this will screw over a significant portion of your existing customers if you go live. This is completely necessary functionality for a authentication provider.

If this goes live, our system will break, and so will countless others. Especially those with databases that rely on emails being unique.

The problem is that it is not currently possible to replicate the behaviour of the old account linking rule with the new action system, this is because it is not possible to seamlessly switch the user to the primary account after linking has happened.

The code below should work, but it does not. It links the accounts, but the user starts his/her session with the secondary account, which at this point does not even exist. This leads to all sorts of wacky behaviour.

The extension can not replicate the necessary behaviour either, as there is no way to disable the option that lets the user proceed without linking.

exports.onExecutePostLogin = async (event, api) => {
  
	const ManagementClient = require("auth0").ManagementClient;
    const DOMAIN = event.secrets.DOMAIN;
	const CLIENT_ID = event.secrets.CLIENT_ID;
	const CLIENT_SECRET = event.secrets.CLIENT_SECRET;

	const management = new ManagementClient({
		domain: DOMAIN,
		clientId: CLIENT_ID,
		clientSecret: CLIENT_SECRET
	});

	let currentAccount = event.user;

  let accounts = await management.getUsersByEmail(currentAccount.email);
  
  if (accounts.length > 2) {
    api.access.deny("[!] Rule: Multiple user profiles already exist - cannot select base profile to link with");
    return;
  } else if (accounts.length === 0) {
    api.access.deny("Unable to login, please contact support if this problem persists");
    return;
  } else if (accounts.length === 2) {
    
    const sorted = accounts.sort((a,b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
    const originalUser = sorted[0];
    const newUser = sorted[1];

    // logging back in with original user, confirm
    if (currentAccount.user_id === originalUser.user_id) {
      return;
    }

    // one profile exists, new one is not yet verified
    if (!originalUser.email_verified || !newUser.email_verified) {
      api.access.deny("Please verify your email before logging in.");
      return;
    }

    const provider = newUser.identities[0].provider;
    const providerUserId = newUser.identities[0].user_id;

    originalUser.identities = await management.linkUsers(originalUser.user_id, {
      provider: provider,
      user_id: providerUserId
    });

    event.user = originalUser;
    
    return {
      user: originalUser
    }
  }
};

I see three potential solutions:

  1. Don’t deprecate the rules system, at the very least push it back until this is resolved, and everyone has had enough time to migrate away after it is possible to do so (Currently there is no way out).
  2. Allow the account linking extension to force the users to either link accounts or abandon the signup.
  3. Fix the Action system so that it can replicate the behaviour of the rule system.
2 Likes

I know this is many months old now, but we are running into the same issue currently, were you able to find any way around this behavior?

I’m having this same issue now, linking the accounts post login logs you in with the secondary rather than the primary.

+1 on having this fixed

I’ll throw my +1 to this for visibility - Because of account linking limitations in Auth0 Actions, we are forced to use a mixture of Auth0 Rules + Auth0 Post-Login flow Actions.

However, this mixture of Rules + Actions leads to unexpected behavior when users initiate account linking for their new accounts.

Although we set the user object and context.primaryUser value to the user’s existing primary account in the Auth0 Rule, the subsequent Auth0 Actions in the Post-Login flow still has the user’s secondary account information in the event.user object.
If there are any api.user.setAppMetadata or api.user.setUserMetadata calls in the Auth0 Actions, the login flow breaks since the secondary account is no longer available.

2 Likes

What’s the status on this? Is there a workaround?

I am also interested in this topic.

Below is my rule workaround attempt (WIP). Some context… we migrated the users into a Auth0 database and have set up a rule to detect social logins with the same email as in the migrated data.

async function (user, context, callback) {
    const ManagementClient = require('auth0').ManagementClient;
    const management = new ManagementClient({
        token: auth0.accessToken,
        domain: auth0.domain
    });

    console.log(user);

    if (!user.user_id.startsWith("auth0|")) {
        // link social account with migrated
        try {
            const users = (await management.getUsersByEmail(user.email)) || [];
            const dbUsers = users
                .filter(u => u.user_id !== user.user_id)
                .filter(u => u.user_id.startsWith("auth0|"));

            if (dbUsers.length === 1) {
                const migratedUser = dbUsers[0];
                const linkedUser = await management.linkUsers(migratedUser.user_id, { user_id: user.user_id, provider: "google-oauth2" });
                console.log(linkedUser);

                context.primaryUser = migratedUser.user_id;
            }
        } catch (e) {
            console.error("Unable to link accounts", e);
        }
    }

    console.log(context);

    callback(null, user, context);
}

There is some code omitted at the end that fetches the permissions from the DB user and puts them in the context.

hey, I had the same issue but was able to solve it with some limitations.

Please check my reply here.

(Basically the difference the original approach is to invert the linking order)

Our use case is a bit different, but we also rely on the ability to switch the user at login.

We won’t be able to port rules to actions without this critical feature.

This might be helpful:

2 Likes

Hey there!

As this topic is related to Actions and Rules & Hooks are being deprecated soon in favor of Actions, I’m excited to let you know about our next Ask me Anything session in the Forum on Thursday, January 18 with the Rules, Hooks and Actions team on Rules & Hooks and why Actions matter! Submit your questions in the thread above and our esteemed product experts will provide written answers on January 18. Find out more about Rules & Hooks and why Actions matter! Can’t wait to see you there!

Learn more here!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.