Angular 1.x Linking Accounts

Sample Project

Download this sample project configured with your Auth0 API Keys.

There may be situations when your users want to log in with multiple accounts that they own. In these cases, you may want to link these accounts together so that they are all reflected in the user's Auth0 profile. For example, if a user has signed up with an email and password (which provides very little information about them), you can ask them to link their account to an OAuth provider like Facebook or Google to gain access to their social profile. For a detailed description of linking accounts, see the full documentation.

Linking Accounts

To link accounts, call the link a user account endpoint. You will need the id_token and user_id of the primary account and the id_token of the secondary account.

To differentiate the login from the linking login, you will need to create a second instance of Auth0Lock to obtain the id_token of the secondary account.

Since all instances of Auth0Lock will receive the authenticated event, you will need a way to determine if authentication came from the primary login or the linking login.

You can use the auth.params property of the options object of Auth0Lock to add a state property with the value 'linking'.

// components/auth/auth.service.js

(function () {

  'use strict';

  angular
    .module('app')
    .service('authService', authService);

  function authService(lock, authManager, $q, $http) {
	
    function linkAccount() {
      try {
        var profile = JSON.parse(localStorage.getItem('profile'));
        var token = localStorage.getItem('id_token');
      } catch (e) {
        return false;
      }

      var options = {
        rememberLastLogin: false,
        auth: {
          redirect: false,
          params: {
            scope: 'openid'
          }
        }
      };

      var lockLink = new Auth0Lock('YOUR_CLIENT_ID', 'YOUR_AUTH0_DOMAIN', options);
      var deferred = $q.defer();

      lockLink.on('authenticated', function (authResult) {
        // do linking accounts
      });

      lockLink.show();
      return deferred.promise;

    }

    return {	 
      linkAccount: linkAccount
    }
  }
})();

Now that the second user is authenticated, the accounts can be linked.

// components/auth/auth.service.js

(function () {

  'use strict';

  angular
    .module('app')
    .service('authService', authService);

  function authService(lock, authManager, $q, $http) {

    lockLink.on('authenticated', function (authResult) {
    
      $http({
        method: 'POST',
        url: 'https://YOUR_CLIENT_ID/api/v2/users/' + profile.user_id + '/identities',
        headers: {
          Authorization: 'Bearer ' + token
        },
        data: {
          link_with: authResult.idToken
        }
      }).then(function () {
        lockLink.hide();
      
        lock.getProfile(token, function (error, profile) {
          if (!error) {
            localStorage.setItem('profile', JSON.stringify(profile));
            deferred.resolve(profile);
          } else {
            deferred.reject(error);
          }
        });    
      });
    });
  }
})();

This function posts to the API, passing the link_with parameter with the JWT value in the body. It then fetches the profile on success to check that the accounts are linked.

To begin the linking process, call the linkAccount method.

// components/home/home.controller.js

(function () {

  'use strict';

  angular
    .module('app')
    .controller('HomeController', HomeController);

  function HomeController(authService) {

    function linkAccount() {
      authService.linkAccount()
        .then(function (profile) {
          vm.profile = profile;
          refreshIdentities();
        })
    }
  }

})();

Linked Accounts User Profile Information

The user profile contains an array of identities which includes the profile information from linked providers.

To view a user's identities, access the Users page on the Auth0 dashboard, select a user, and scroll down to identities.

This example shows a user with a linked Google account:

User identities

If you fetch the profile after linking accounts, this same information will be available.

You can display this information and provide an Unlink button:

<!-- components/home/home.html -->
	
<div class="identities-wrap" ng-if="isAuthenticated">
  <button class="btn btn-primary" ng-click="vm.linkAccount()">Link Account</button>
  <ul class="list-group identities-list">
    <li class="list-group-item identities-item" ng-repeat="identity in vm.identities">
      <img ng-src="{{identity.profileData.picture}}"/>
      <span>{{ identity.profileData.name || identity.profileData.email }}</span>
      <button class="btn btn-danger" ng-click="vm.unLinkAccount(identity)"><i class="glyphicon glyphicon-trash"></i></button>
    </li>
  </ul>
</div>

The user's primary identity can be filtered by putting in a function to refresh the identities.

// components/home/home.controller.js

(function () {

  'use strict';

  angular
    .module('app')
    .controller('HomeController', HomeController);

  function HomeController(authService) {

    function refreshIdentities() {
      vm.profile.identities.shift();
      vm.identities = vm.profile.identities;
    }
  }

})();

Unlinking Accounts

You can dissociate a linked account by calling the unlink a user account endpoint using the primary user_id, the provider, and user_id of the identity to unlink.

// components/auth/auth.service.js

(function () {

  'use strict';

  angular
    .module('app')
    .service('authService', authService);

  function authService(lock, authManager, $q, $http) {

    function unLinkAccount(identity) {
      try {
        var profile = JSON.parse(localStorage.getItem('profile'));
        var token = localStorage.getItem('id_token');
      } catch (e) {
        return false;
      }

      var deferred = $q.defer();

      $http({
        method: 'DELETE',
        url: 'https://YOUR_CLIENT_ID/api/v2/users/' + profile.user_id + '/identities/' + identity.provider + '/' + identity.user_id,
        headers: {
          Authorization: 'Bearer ' + token
        }
      }).then(function () {

        lock.getProfile(token, function (error, profile) {
          if (!error) {
            localStorage.setItem('profile', JSON.stringify(profile));
            deferred.resolve(profile);
          } else {
            deferred.reject(error);
          }
        });

      });

      return deferred.promise;
    }

    return {
      unLinkAccount: unLinkAccount
    }
  }
})();
Previous Tutorial
5. User Profile
Next Tutorial
7. Rules
Use Auth0 for FREECreate free Account