The Registration Handler
Module 3 of 5 in the chapter The Mirror Image: Social Sign-On and Delegated Authentication, chapter 10 of Securing Salesforce: Identity and Access. Each module stands on its own.
The question this module answers: When someone signs in through an auth provider, who decides which Salesforce user she becomes?
Who does she become?
Section titled “Who does she become?”Module 1 ended with Salesforce holding what the provider says about Priya: an email address, a name, whatever she consented to share. Google has told Salesforce who she is at Google. It hasn’t told Salesforce who she is in Salesforce.
Is she a customer you already have? Is she new? Which profile, which licence? Should she be let in at all? Salesforce can’t guess. You write the answer, and it’s called the registration handler. To use an auth provider for single sign-on, you have to have one (S3).
What arrives
Section titled “What arrives”Different providers send different things back. Salesforce takes whatever the provider returned and puts it into one shape, the Apex class Auth.UserData (S3, S4): her email, her name, her username at the provider, and so on. Everything else the provider sent is kept as raw text in its attributeMap (S4). If the provider sent an ID token or a user info answer, those are there too (S4).
So your handler gets the same shape whether she came from Google, Microsoft or another Salesforce org. What it does with it is up to you.
Two methods
Section titled “Two methods”If I’m implementing social sign-on, what class do I need to implement? The registration handler. And what two methods does it have? Create user and update user. That one comes up on the exam.
In Apex, the class implements Auth.RegistrationHandler (S4):
| Method | When it runs | What it does |
|---|---|---|
User createUser(ID portalId, Auth.UserData userData) | The first time she signs in through this provider | Returns a User. “It can be a new user that hasn’t been inserted… or it can represent an existing user record… If it’s a new User object, Salesforce inserts a user record for you” |
void updateUser(ID userId, ID portalId, Auth.UserData userData) | Every time after | Updates her user: “called if the user has logged in before with the authentication provider and then logs in again” |
portalId is for an Experience Cloud site or portal set on the auth provider; it can be empty if there isn’t one (S4).
Why update every time? Because every time she logs in, something might have changed: a new email, a new phone. updateUser is where you carry that across, if you want to.
The user it runs as
Section titled “The user it runs as”The handler doesn’t run as Priya; she isn’t anyone yet. On the auth provider, Execute Registration As names the user it runs as, and that user needs the Manage Users permission (S5). Salesforce’s advice: in production, typically create a system user for it, so that whatever the handler does, such as creating a contact, can be traced back to registration (S5).
The checks
Section titled “The checks”Here’s the warning from my Google video. A basic handler will create a new user for anyone who signs in. Anyone with a Google account. That’s not what you want.
So before createUser returns anyone, it needs checks and balances:
- May she come in at all? Not everyone with a social account should get a user. Maybe only people you invited, or people whose email is already on a contact.
- Is she someone you already have? Match her to an existing user before you create a new one, or she’ll end up with two.
- As whom? Which profile, which permission sets, and which licence. Licences run out, and every user you create uses one.
- Can you trust what you’re matching on? An email address from a provider is only as good as that provider’s check of it.
If the answer is no, don’t return a user. Throw an exception instead, and Salesforce shows the person an error (S4).
Setup can automatically create a registration handler template for you, an Apex class to start from. Salesforce’s own words: “Edit this class later, and modify the default content before using it” (S5). A template is a start, not a solution.
Don’t trust an ID token you haven’t checked
Section titled “Don’t trust an ID token you haven’t checked”This is a hard truth to know, in Salesforce’s words. When the provider sends an ID token, Salesforce hands it to your handler, but: “Salesforce doesn’t validate the ID token. To validate it, use methods in the Auth.JWTUtil class” (S4). For an OpenID Connect auth provider, it checks the issuer and the user info, but “The signature of the ID token isn’t validated” (S6).
So if your handler makes a decision on a claim from the ID token, say her email or a group she’s in, validate the token first, with the provider’s public keys (S4). Chapter 9 said the same from the app’s side: check the ID token’s signature.
Apex or Flow
Section titled “Apex or Flow”You don’t have to write code. A registration handler can be an Apex class or a flow (S3, S5). Salesforce compares them (S3):
- Flow: built and maintained with clicks, no developer needed; it adds and removes permission sets in one transaction, “which helps you avoid mixed DML errors that are common with Apex”; and it has an action to pull a value out of the provider’s nested JSON. It “supports most use cases”.
- Apex: “supports more complex use cases”, but needs a developer to build and maintain it.
For a flow, choose the flow type Identity User Registration, start from the Authentication Provider User Registration template, and set a default profile on the auth provider (S5).
A skeleton
Section titled “A skeleton”Here’s the smallest useful handler: one that only lets in people who already have an active user, matched by email, and never creates anyone. It’s the one this chapter’s practice uses between your two lab orgs. It’s a sketch to read, not production code: before you use anything like it, run it in a sandbox and write its tests.
global class MatchExistingUsersHandler implements Auth.RegistrationHandler {
global class RegistrationException extends Exception {}
// The first time: find her existing user, or refuse. global User createUser(Id portalId, Auth.UserData data) { List<User> matches = [ SELECT Id FROM User WHERE Email = :data.email AND IsActive = true LIMIT 2 ]; if (matches.size() != 1) { throw new RegistrationException('No account found. Ask your administrator for access.'); } return matches[0]; }
// Every time after: this handler changes nothing. global void updateUser(Id userId, Id portalId, Auth.UserData data) { }}Read it with the checks in mind. It refuses if there’s no match, and it refuses if there are two, rather than guess. It returns an existing user, so Salesforce inserts nothing. And it trusts the email because, in the practice, the identity provider is your own org. With a social provider, you’d want more than an email.
Chapter 12 puts this beside its SAML cousin, just-in-time provisioning, where the identity provider sends the user’s details in the assertion and Salesforce creates or updates the user on the fly.
Test knowledge. In my experience, know that social sign-on needs a registration handler, the
Auth.RegistrationHandlerinterface, and its two methods,createUserandupdateUser.
What’s next
Section titled “What’s next”Module 4: where it fits. Customers and partners, not staff.
What an architect decides here
Section titled “What an architect decides here”- Who may come in through each auth provider, and what happens to everyone else.
- How a person is matched to an existing user, and on what you can trust.
- Which profile, permission sets and licence a new user gets, if any.
- Apex or Flow, and who will maintain it.
- The system user the handler runs as.
Explore
Section titled “Explore”- Create an Authentication Provider Registration Handler (opens in a new tab) (Salesforce Help, Winter ‘27; checked 2026-11-07)
- RegistrationHandler Interface (opens in a new tab) (Apex Reference Guide; checked 2026-11-07)
