1

I'm stuck in deleting ThirdPartyAccountLink record in RegistrationHandler apex class for SSO. After contacting salesforce support I got delete access on ThirdPartyAccountLink object.

My class is working as expected when user login first time but when I change the user id for that user and try to login it gave me below error: "Delete failed. First exception on row 0 with id 0Jr0v00000000FQCAY; first error: UNKNOWN_EXCEPTION, An unexpected error occurred. Please include this ErrorId if you contact support: 788178633-264969 (188355293): []"

After changing Id of User A from xxx to yyy, then User A should land on profile of user having YYY id. Currently even after changing Id User A still landing on profile of xxx id.

Please let me know if any confusion is there.

Code :


    global class RegistrationHandlerSSO implements Auth.RegistrationHandler {
    
        global User createUser(Id portalId, Auth.UserData data) {
    
            //Querying all users
            List<User> userList = new List<User>([
                SELECT  Id
                FROM    User
                WHERE   Id =: data.attributeMap.get('alt_username') AND
                        IsActive = true and
                        SFDC_License_Type__c = 'Customer Community Plus Login'
            ]);
    
            User uId;
            boolean generateUser = true;
    
            for (User u:userList) {
    
                //Checking that current user is already there in system or not.
                //If yes, performing below operations
                if (u.Id == data.attributeMap.get('alt_username')) {
    
                    Id userIds= u.Id;
    
                    //Fetch ThirdPartyAccountLink records associated with this user and delete it using
                    // Auth.AuthToken.revokeAccess() method
                    List<ThirdPartyAccountLink> thirdPartyActLink = new List<ThirdPartyAccountLink>(
                        [SELECT Handle, Provider, SsoProviderName, UserId, ThirdPartyAccountLinkKey,
                                user.contact.Account.Id, remoteIdentifier, SsoProvider.id
                         FROM   ThirdPartyAccountLink
                         WHERE  UserId =: userIds
                         LIMIT  1]);
    
                    if(!thirdPartyActLink.isEmpty())
                    Auth.AuthToken.revokeAccess(
                                thirdPartyActLink[0].SsoProvider.id,
                                thirdPartyActLink[0].Provider,
                                thirdPartyActLink[0].UserId,
                                thirdPartyActLink[0].remoteIdentifier
                            );
    
                    //Marking this boolean as false to avoid creating new user
                    generateUser = false;
    
                    //if user is aleadythere in system paas it to updateUser() method to avoid linking
                    // Id change
                    updateUser(u.Id, portalId, data);
                    uId = u;
                }
            }
    
            return(uId);
        }
    
        global void updateUser(Id userId, Id portalId, Auth.UserData data) {
    
            // checking for ID whether it same as logged in community user. if not then update it
            if(userId != data.attributeMap.get('alt_username')) {
                userId = data.attributeMap.get('alt_username');
            }
    
            List<User> userList = new List<User>([
                SELECT  Id
                FROM    User
                WHERE   Id =: userId
            ]);
    
            for (User u:userList) {
    
                List<ThirdPartyAccountLink> thirdPartyActLink = new List<ThirdPartyAccountLink>(
                        [SELECT Handle, Provider, SsoProviderName, UserId, ThirdPartyAccountLinkKey,
                                user.contact.Account.Id, remoteIdentifier, SsoProvider.id
                         FROM   ThirdPartyAccountLink
                         WHERE  UserId =: u.Id
                         LIMIT  1]);
    
                    if(!thirdPartyActLink.isEmpty()) {
                        try {
                            Auth.AuthToken.revokeAccess(
                                thirdPartyActLink[0].SsoProvider.id,
                                thirdPartyActLink[0].Provider,
                                thirdPartyActLink[0].UserId,
                                thirdPartyActLink[0].remoteIdentifier
                            );
                        } catch (System.DmlException e) {
                            System.debug('@@@Error while deleteImmediate::'+e);
                            System.Debug('Cause: ' + e.getCause());
                            System.Debug('TypeName: ' + e.getTypeName());
                            System.Debug('getDmlFieldNames: ' + e.getDmlFieldNames(0));
                            System.Debug('getDmlFields: ' + e.getDmlFields(0));
                            System.Debug('getDmlId: ' + e.getDmlId(0));
                            System.Debug('getDmlMessage: ' + e.getDmlMessage(0));
                            System.Debug('getDmlType: ' + e.getDmlType(0));
                            System.Debug('getNumDml: ' + e.getNumDml());
                            System.Debug('Message: ' + e.getMessage());
                        }
                    }
    
                    User u2 = new User(id=u.Id);
                    update(u2);
            }
        }
    }

Can someone please help me on this? Any help will be appreciated.

5
  • 1
    Try revoking instead of deleting
    – identigral
    Jul 29, 2020 at 17:03
  • I did that as well, but it gave me error as "We can’t log you in because of an authentication error." I want user to be able to login with new ID instead of giving authentication error, can it be possible?
    – Snehal
    Jul 30, 2020 at 7:23
  • 1
    Return the right User from createUser(...). If the User record already exists and you want to use that record instead of creating a new one, locate that record and return it.
    – identigral
    Jul 30, 2020 at 7:46
  • 1
    Revoking method works for scenario when User Id is changed. I'll check for newly created user, whether it is able to login or not after these change in code
    – Snehal
    Jul 30, 2020 at 8:13
  • 1
    Thanks @identigral , by making few code changes it worked as expected. I've update my code in question, which is working now.
    – Snehal
    Aug 2, 2020 at 16:43

1 Answer 1

1

@Snehal not completely sure whether this is still relevant. But the solution could be in providing the Provider name to revokeAccess() in lowercase.

Some other useful things to know:

  • deleteImmediate() currently (March '21) faces a known bug regarding TPAL destruction, so SF supports shared to only use revokeAccess();
  • revokeAccess() requires the Provider name to be lowercase (even while not documented)
  • insertImmediate() on TPALs requires the TPAL Unique key to not exist in the system yet. In other words, when reparenting, make sure the original record is deleted/revoked access before trying to insert the same TPAL to another User

In case you like to read more on this, please find this post where I list several challenges I faced when implementing: https://www.foxy-solutions.com/salesforce/reparent-thirdpartyaccountlinks/

3
  • 1
    While this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
    – identigral
    Mar 4, 2021 at 18:56
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review Mar 5, 2021 at 1:20
  • 1
    @MohithShrivastava and identigral thanks for your replies. I thought the answer already provided the direct response sufficiently, but please find the answer to be updated and contain a summary of findings shared in the blog post.
    – Reinier
    Mar 6, 2021 at 14:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .