Enabling MFA on Experience Sites
Enable Multi-Factor Authentication for Experience Site (Community) users by deploying the correct permission sets and verifying the platform-handled MFA challenge flow.
Scope
In scope:
- Deploying
ForceTwoFactorpermission set for community users - Deploying
ApiEnabledpermission set (required for post-login API calls) - Assigning permission sets to community users
- Troubleshooting MFA not appearing on login
- Customizing MFA/login page branding via NetworkBranding metadata
Out of scope — delegate elsewhere:
- Building custom login UI →
experience-ui-bundle-frontend-generate - Creating generic permission sets →
platform-permission-set-generate - Assigning permission sets (if already deployed) →
dx-org-permission-set-assign - Deploying metadata to org →
platform-metadata-deploy - Org-wide MFA for internal Salesforce users → Setup > Identity Verification (not a skill)
Prerequisites
Before using this skill, ensure the following are already in place:
Note: This skill does NOT handle org setup, license provisioning, or Experience Cloud site creation. If these prerequisites are missing, set them up first via Setup > Digital Experiences > All Sites > New, or deploy your site's base app bundle.
Required Inputs
Gather before acting:
Critical Domain Knowledge
These facts are non-obvious and frequently cause confusion:
Workflow
Step 1: Resolve the target site (Network)
These are React Experience Sites, so both permission sets are always deployed —
ForceTwoFactor (enforces MFA) and ApiEnabled (React sites make post-login API
calls).
Resolve the Experience Site's real name and Id from the org — do not assume the
uiBundles/ app folder name is the site name. They are frequently different, and the
site name must come from the org (the deploy target), not the local project.
<site-name> and <NETWORK_ID> below come from here:
- One site → use its
Nameas<site-name>andIdas<NETWORK_ID>. - Multiple sites → ask the user which one (show the names).
- Zero sites → the site isn't deployed yet; stop and tell the user (see Prerequisites).
Step 2: Generate permission set files
First, detect the project's source directory:
Use the result as <source-dir> (e.g. force-app/main/default) for all commands below.
Write both permission sets (React Experience Sites always need both):
- Read
assets/MFA_Required_For_Community.permissionset-meta.xml - Write it to
<source-dir>/permissionsets/MFA_Required_For_Community.permissionset-meta.xmlin the user's project - Read
assets/API_Enabled_For_Community.permissionset-meta.xml - Write it to
<source-dir>/permissionsets/API_Enabled_For_Community.permissionset-meta.xml
Step 3: Deploy to org
Step 3b: Validate community profile is a network member
Before assigning permission sets to users, verify that the community profile is registered as a site member. Without this, community users cannot log in at all (and MFA will never trigger).
- Query current network members:
- Check if the community profile is in the list:
- If the profile is NOT a member, add it to the
.network-meta.xml:
- Deploy the updated network metadata:
IMPORTANT: If the community profile is not a member of the network, users with that profile CANNOT log in — meaning MFA will never be triggered even if permission sets are correctly assigned. This is a common misconfiguration in freshly deployed orgs.
Step 3c: Validate guest profile has Apex class access for login
The site login page runs as the guest user (unauthenticated). If the guest profile doesn't have access to login Apex classes, users will get FORBIDDEN: You do not have access to the Apex class named: UIBundleLogin and can never reach the MFA challenge.
- Find the site guest user profile:
- Grant access to any missing UIBundle login classes. The six classes are
UIBundleLogin,UIBundleAuthUtils,UIBundleForgotPassword,UIBundleChangePassword,UIBundleRegistration, andUIBundleSocialLoginConfig. Run the anonymous Apex inreferences/setup.md("Grant Guest Profile Apex Class Access") — it diffs existing access and inserts only what's missing — or deploy<classAccess>entries for the same classes to the guest profile metadata XML.
IMPORTANT: This is NOT MFA-specific, but without it the login page itself is broken. The skill must validate this to ensure MFA can actually be triggered. Common in freshly deployed orgs where the guest profile didn't get full class access.
Step 4: Assign permission sets
Find community users:
If community users exist:
Find the permission set IDs:
Assign to each user:
Alternatively, delegate to dx-org-permission-set-assign skill:
If no community users found:
Ask the user: "No active community users found in this org. Would you like me to create a test community user so you can verify MFA is working?"
If user agrees, create a test community user:
- Find the community profile from the site's network configuration:
- Create an Account (required as community user parent):
- Create a Contact (linked to the Account):
- Create the User with the community profile:
- Set a password for the test user:
- Assign both permission sets to the new user:
Report the credentials to the user so they can test:
"Created test user:
mfa.testuser@<site-name>.testwith password:<generated-password>. You can use these credentials to verify MFA on your site."
IMPORTANT: Community users require Account → Contact → User hierarchy. Creating a User without a linked Contact on a community profile will fail.
Step 5: Register the permission sets as site members (networkMemberGroups)
networkMemberGroupsis a membership/access gate — it lists the profiles and permission sets whose holders count as members of the site. It does not assign MFA to users. Assignment happens in Step 4 (per user); register the sets here so assigned users still count as site members.
- Find the existing
.network-meta.xmlin the project:
-
Read the file and locate the
<networkMemberGroups>section. -
Add the permission set entries (if not already present):
IMPORTANT: Network metadata deploys are declarative — whatever you deploy becomes the full state. Do NOT create a new
.network-meta.xmlfrom scratch. Always read the existing file and add entries to it.
- Deploy the updated network metadata:
Step 6: Publish and verify
Verification steps:
- Open incognito browser
- Navigate to site login page
- Enter credentials → MFA challenge page should appear (on vforcesite domain)
- Complete MFA → should land on the site, logged in
Rules
Gotchas
Output Expectations
Files generated in the user's project:
When summarizing what was done, do NOT claim that adding permission sets to
<networkMemberGroups>(or updating the network) causes new or self-registered users to automatically get MFA. It does not —networkMemberGroupsonly defines site membership. MFA is enforced only for users the permission set has been explicitly assigned to (Step 4). Report network changes as "registered the permission sets as site members," not as auto-assignment.


