Adding single sign-on (SSO) to Salesforce Organizations helps streamline the login process for end users while also enhancing security. In this tutorial, we will share how to add Descope SSO authentication to a Salesforce Org using OpenID Connect, highlight some interesting use cases of this integration, and introduce how to use Descope Flows with Experience Cloud apps.
Setting up Descope SSO for Salesforce
We’ve broken down the setup process into the following sections:
Create and configure a new Auth Provider
Modify registration handler to create and update users correctly
User attribute mapping
Add Auth Provider (Descope) to login screen
User permission sets and profiles
Create a new Auth Provider
Search Auth. Providers under Setup in your Salesforce Org. Then, select New and create a new Auth Provider.
You’ll need to use the following information to correctly configure your Auth Provider:
Name: Descope (or can be anything else you want).
Consumer Key: This is your Descope Project ID, found under Project Settings in the Descope Console.
Consumer Secret: This is the Descope Access Key, created under Access Keys in the Descope Console.
Authorize Endpoint URL:
https://api.descope.com/oauth2/v1/authorize
Token Endpoint URL:
https://api.descope.com/oauth2/v1/token
User Info Endpoint URL:
https://api.descope.com/oauth2/v1/userinfo
Custom Logout URL:
https://api.descope.com/oauth2/v1/logout
Once you have filled in the fields above, click on Automatically create a registration handler template, under Registration Handler.
When Salesforce is set up to allow for single sign-on (SSO) using OIDC, this registration handler (which will be automatically generated) helps determine what to do when a user logs in with their external identity.
The auto-generated registration handler will need to be edited, and will be covered later in the guide. For now, you can just select the button shown above.
When entering your details, you’ll also need to select a user under Execute Registration As. This field determines which Salesforce user's permissions are leveraged when running the methods inside the registration handler.
In order to configure this, select the magnifying glass and then select a user that is a System Administrator or someone who has the proper permissions to run Apex classes, as well as create and update user records.
Once you’ve filled in Execute Registration As, go ahead and click Save, and then re-click on the new Auth Provider that you have created. You should be taken back to a screen that looks like the one below, where you can see all of the new Auth Provider details:
Modify registration handler
The next step in adding Descope SSO to Salesforce is to modify the registration handler.
To better understand this, it’s important to understand the main responsibilities of a Registration Handler in Salesforce:
User Creation: If a user logs in with Descope and doesn't have a user account in Salesforce, the registration handler will create a new Salesforce user record with the information gathered from Descope (such as the email and name).
User Lookup: If a user logs in with Descope and does have a corresponding Salesforce account, the registration handler will identify and return that user.
User Update: This part of the registration handler is optional and depends on if you want newly updated user information to be inserted into each Salesforce user record upon login. For instance, if an attribute like the user's title changes in Descope (and it’s correctly assigned), it can be updated in Salesforce during the SSO process.
You can read more about the registration handler interface on this Salesforce docs page.
In this section, we will cover how to modify the registration handler (also known as an Apex Class) so that we can easily create and lookup users based on their email, as well as modify new data that can potentially come in from Descope.
After selecting the Auto Generated apex class and clicking Edit, copy over some boilerplate code that will handle all of the registration handler responsibilities discussed above. The code would look something like this:
global class AutocreatedRegHandler1692036068599 implements Auth.RegistrationHandler{
global User createUser(Id portalId, Auth.UserData data){
User u;
// Try to find an existing user first
List<User> existingUsers = [SELECT ID FROM User WHERE FederationIdentifier =: data.email];
System.debug('data: ' + data);
System.debug('email from data: ' + data.email);
if (existingUsers.size() > 0) {
u = existingUsers[0];
} else {
// If no user exists, create a new one
u = new User();
String firstName = data.attributeMap.containsKey('name') ? data.attributeMap.get('name') : 'DefaultFirst'; // OIDC uses name instead of firstName as the attribute key
String lastName = data.attributeMap.containsKey('family_name') ? data.attributeMap.get('family_name') : 'DefaultLast'; // OIDC uses family_name instead of firstName as the attribute key
u.Username = 'DefaultUser' + '@example.com'; // Fill in your own username logic
u.Email = data.attributeMap.containsKey('email') ? data.attributeMap.get('email') : 'default@email.com';
u.FirstName = firstName;
u.LastName = lastName;
u.FederationIdentifier = data.email;
u.Alias = (firstName + lastName).length() > 8 ? (firstName + lastName).substring(0, 8) : (firstName + lastName); // Alias logic
u.ProfileId = '00eHu000002sq8b'; // Insert your own Profile ID
u.TimeZoneSidKey = 'GMT';
u.LocaleSidKey = 'en_US';
u.EmailEncodingKey = 'UTF-8';
u.LanguageLocaleKey = 'en_US';
// If working with Communities or Portals, you might also need to set additional fields like AccountId, ContactId, etc.
insert u;
}
return u;
}
global void updateUser(Id userId, Id portalId, Auth.UserData data){
User u = [SELECT Id, Email, FirstName, LastName FROM User WHERE Id =: userId LIMIT 1];
// Update the user's information based on the incoming data
u.Email = data.attributeMap.containsKey('email') ? data.attributeMap.get('email') : u.Email;
u.FirstName = data.attributeMap.containsKey('name') ? data.attributeMap.get('name') : u.FirstName;
u.LastName = data.attributeMap.containsKey('family_name') ? data.attributeMap.get('family_name') : u.LastName;
// Update other fields as necessary
update u;
}
}
Copy the code into the code editor like so:
Click Save, and your registration handler should at least be able to create a user with the basic attributes listed in the code above.
Keep in mind that your implementation might be different depending on the custom user attributes you want to assign to your new users, time zones, locale settings, and so on. Refer to the comments in the code snippet above to see all the options that could be changed to match your specific implementation.
If you’re wondering how to get the Profile ID you want to associate your new users with, you can click on the Profile you want under Setup > Profiles, and copy the Profile ID from the URL you’ll see at the top of the screen.
At this point, you can either skip to the Profile Permissions section of the guide, or you can read more about how to beef up your registration handler to also include JWT custom claims and information you’re passing through to Salesforce from Descope.
User attribute mapping with OIDC
Custom attributes allow for extended functionality in terms of personalizing user data. These are unique attributes or fields that your business might use and which are not available by default in Salesforce or Descope.
When using OIDC with Descope, you will receive a JSON Web Token (JWT). This token contains claims about the authenticated user, which can include both standard and custom attributes.
To map these attributes in your Apex class, modify your Apex Class to use the AttributeMap function, which is part of the UserData class.
u.<some random Salesforce attribute key> = data.attributeMap.containsKey('<Descope custom claim key>') ? data.attributeMap.get('<Descope custom claim key>') : 'defaultValue';
With the AttributeMap
function, you can map whatever custom claims or user attributes that you would like. Just remember that the user attribute must exist and already be configured for your Salesforce users, otherwise you will receive an error when the Apex handler runs this code.
Beyond attribute mapping, if you’re interested to learn more about the different OIDC configurations that Salesforce supports, check out their documentation.
Add Descope SSO to login screen
Once you’ve modified the registration handler, you’ll need to allow your users to to sign in with Descope with a button on the Salesforce login screen.
In order to edit the main login screen to include this, you need to change your Salesforce settings.
Search for My Domain, and select Edit under Authentication Configuration:
Then select the new Auth Provider you created (for this tutorial, we selected Descope):
Once that’s selected, you can save this configuration. Now you should see Login with Descope as an option the next time you log in to your Salesforce Organization.
If you wish to enforce Descope SSO in this screen, you can do that under My Domain. Once you’re in My Domain, select Edit, and check the Prevent login from https://login.salesforce.com checkbox.
A full guide on how to enforce SSO and control the methods of authentication within your Salesforce Organization can be found on their documentation page.
Next up, we share how to configure your profile permissions correctly in order to use SSO.
Profile permissions
When using the registration handler, it’s vital to ensure that the user being used to run the Apex class has the correct profile permissions. The user that controls and runs the registration handler is the user that was defined under Execute Registration As in the OIDC configuration page.
There are unconventional permissions that you may have to change or provide to accomplish this. For example, the SSO will not work if your user is an API-Only User. However, if you need to change anything beyond what this guide mentions, it will be included in the error message (in the URL), when you try to log in via SSO.
Besides seeing an error message relating to other permissions, you might also come across this message if you’re setting up SSO for the first time:
When using registration handlers, your Apex class executor user needs to have the ability to Manage Users. You can provide Manage User access associating your user with API Integration-licensed permission set.
If you’re seeing the error in the screenshot above, follow this next part of the guide to learn how to create an API Integration-licensed permission set.
Allowing API integration permissions
Create an API-Only integration profile and assign a new or existing user to it to handle the registration handler. You can do this by going to Setup > Profile, and selecting New in the top left corner. Then fill in the following information:
Once the profile has been created, open it up and select Assigned Users:
From there, either add a new user or existing user, which will be the user that executes your registration handler Apex class.
Then, you’ll need to create an API integration permission set. Go to Setup > Permission Set, and click New in the top left corner. Then, configure a new permission set as illustrated below:
Once you’ve done that, head to Setup > Users and select the user that will be associated with your registration handler and execute it. When you scroll down, you should see these two sections:
Under Permission Set Assignments, add the new Permission Set you’ve just created. Under Permission Set License Assignments, look for and add Salesforce API Integration.
After that, your page should look something like this:
Once that’s done, you shouldn’t see any more errors when logging in with Descope!
Enhanced security in Experience Cloud applications
Using Descope in conjunction with Experience Cloud can elevate your security posture while maintaining a user-friendly experience. Here is an interesting use case for Descope Flows – our drag & drop workflow engine – when used with an Experience Cloud application.
Scenario: Your enterprise operates on Salesforce Experience Cloud, serving a large audience with access to specialized insights, analytics, or proprietary content. Descope Flows can help safeguard this data.
How Descope Flows help
Dynamic Verification: Depending on the user's profile and the sensitivity of the data being accessed, the Flow can prompt the user for additional authentication factors. This could range from a simple OTP verification to advanced biometrics, determined dynamically based on the context.
User Experience and Trust: Descope Flows can adapt based on a myriad of factors, such as user behavior, geolocation, time of access, and device type.
Audit and Reporting: By utilizing third-party connectors such as Datadog in Descope Flows, you can stream rich data on user access patterns, successful and failed authentication attempts, and more to your observability platform. This information can guide security strategy adjustments and provide insights for compliance and auditing purposes.
Integrating Descope with Salesforce Experience Cloud isn't just about adding a security layer; it's about smartly enhancing the platform's capability while ensuring users have a seamless experience.
Using Descope with Experience Cloud apps
Since we’ve already added Descope as an OIDC Auth Provider with Salesforce, adding Descope SSO to the login page of your Experience Cloud apps is straightforward:
From Setup, in the Quick Find box, enter Sites, and then select All Sites.
Next to your site, click Workspaces.
Select Administration, and then select Login & Registration.
Under Login Page Setup, select an authentication provider to show on the login page.
Save your settings.
To see your changes, click Settings, and then open your site URL in a private (incognito) browser. Your authentication provider appears as a button under the login form. When users click the button, they’re redirected to the provider to log in.
These instructions, as well as the permissions that you will need for configuration, can be found on the Salesforce documentation site.
Once you’ve successfully followed the steps listed in the Salesforce guide, you should be able to access your Experience Cloud application using your Descope Flow, and handle use cases like the one described above.
Conclusion
Descope makes it very easy to add SSO capabilities to your Salesforce Organization, even extending it to Experience Cloud applications. Organizations can implement SSO with Descope for their Salesforce environments for enhanced security, streamlined user management, and a delightful user experience.
The ability to easily modify Descope Flows makes it possible to add risk-based MFA, audit streaming, and step-up authentication without any time-consuming configuration or app changes.
Interested to learn more about Descope? Book time with our auth experts. Not the talking type? Sign up for a Free Forever Descope account and start “descoping” your authentication.