Background: We've created a pseudo-single-sign-on integration between our external cloud program and our Salesforce environment, allowing our users to log in to our Lightning Community Site via a Visualforce page that uses Site methods to log the user in. Long story short, we built a custom API that our external program calls when a user is added to that program, and it automatically creates a Contact and Community User on their associated account in Salesforce, and then sets their password using System.setPassword()
.
Ultimate Problem: The password that we set after user creation does not work.
During some debug testing, we tried to do it directly through Execute Anonymous to see if there was a problem in our apex logic somewhere, the following code executes successfully, but the user is still not able to login with the password afterwards.
Id profId = [SELECT Id FROM Profile WHERE Name = 'Community Knowledge User' LIMIT 1].Id;
Account a = new Account(Name = 'Test5');
insert a;
Contact c = new Contact(AccountId = a.Id,
FirstName = 'Morgan',
LastName = 'Ma',
Email = '[email protected]',
Title__c = 'Administrator');
insert c;
User u = new User(ContactId = c.Id,
Alias = 'MSstA5',
FirstName = c.FirstName,
LastName = c.LastName,
Email = c.Email,
Username = c.Email,
ProfileId = profId,
EmailEncodingKey = 'ISO-8859-1',
LanguageLocaleKey = 'en_US',
LocaleSidKey = 'en_US',
TimeZoneSidKey = 'America/New_York');
insert u;
System.setPassword(u.Id, 'Welcome1*');
If we try to run System.setPassword again in execute anonymous to set their password to Welcome1* again, we receive the UNKNOWN_EXCEPTION: invalid repeated password
error, indicating that the users password IS recognized as already being Welcome1*. However, the password does not work to log the user in either via our Visualforce page OR directly via the standard login page.
If we run System.setPassword
and change it to Welcome2*, the user is suddenly able to login fine. We can then use System.setPassword
to set it back to Welcome1*, which also works fine afterwards, but we cannot get the users password to work if the password was set in the same transaction after the user was inserted - even though Salesforce seems to acknowledge that it is the correct password (by nature of the invalid repeated password error).
I've found 2 similar posts
one suggests that you just need to wait a short time and eventually the password will work because it may be delayed: Setting new user passwords in Apex
However, we have waited for multiple hours now, and the issue persists.
Another post had a curious suggestion of doing a second query and return of the User object: Issue creating user and setting password
However, our code already does something similar, but this suggestion doesn't appear to have any merit or work in this context.
We'd like to avoid creating a future method specifically for the purpose of setting these users passwords, but are struggling to understand why Salesforce is recognizing the password as valid, but not letting the user login. Inspection of the user account shows them as active, not frozen, and the login history does post logs indicating Invalid password was provided, even though the password was set and acknowledged by System.setPassword as Welcome1*. We're concerned with creating a future method for this purpose because there are already future methods occurring in this transaction and we may encounter the future cannot call future issue.
Ultimate Questions: Is this a known issue/limitation within Salesforce? Is there something we are missing? Is there a flag or parameter that we need to set on the user to further 'activate' them that isn't being set during the initial creation or SetPassword call? Why does it work when done in a separate transaction but not when done in the same transaction after insert? It appears to be correct, but recognized as incorrect. The documentation doesn't mention this as a limitation.
u.isActive = true
. Also a thought here, if can you try re-querying the user as soon as you insert and then use the retrieved entity to set the password? Say somethinginsert u; User newUser = [SOQL]; System.setPassword(newUser, <pwd>)