For higher security standards one of the best practices to implement is two-factor authentication. This is the method of adding a second factor to the username and password, where the password is the first factor. The second factor is usually done with a random and time-based one-time password (TOTP), generated on an approved mobile device or an approved email address.

When a user logs in, Salesforce considers the user’s geographic location and browser. If they’re not recognized, Salesforce prompts the user to verify their identity using the highest-priority verification method available for that user.
The following is the order of priority for verification methods.

Verification code generated by a mobile authenticator app connected to the user’s account.

Verification code sent via SMS to the user’s verified mobile device.

Verification code sent via email to the user’s email address.

The user enters the code as a secondary verification of their identity. After verification, the user doesn’t need to provide this information again, unless they log in from a browser or location that isn’t verified by Salesforce.

But sometimes we require a second level of authentication on every login for stronger identity verification. We can enable Two-factor authentications for users by adding “Two-Factor Authentication for User Interface Logins” permission through a Profile or a Permission Sets.

The following are the verification methods:

Verification code generated by a mobile authenticator app connected to the user’s account.

Verification code sent via SMS to the user’s verified mobile device.

Verification code sent via email to the user’s email address.

Here is an example of two-factor authentication using login flow, which will send an one-time password (OTP) via email to the user’s email address.

Create “LoggedInUserId” Formula – Drag and drop Formula from Resources – Give the Unique name “LoggedInUserId” – And put the value “$User.Id” as shown in the below screenshot.

Create “OTP” Variable – Drag-and-drop Variable from Resources – Give the Unique name “OTP” as shown in the below screenshot.

Create “UserEmailAddress” Variable – Drag and drop Variable from Resources – Give the Unique name “UserEmailAddress” as shown in the below screenshot.

Create “UserFirstName” Variable – Drag and drop Variable from Resources – Give the Unique name “UserFirstName” as shown in the below screenshot.

Create “UserName” Variable – Drag and drop Variable from Resources – Give the Unique name “UserName” as shown in the below screenshot.

Create “TwoFactorAuthenticationLoginOTP” Text Template – Drag and drop Text Template from Resources – Give the Unique name “TwoFactorAuthenticationLoginOTP” – And put the “{!OTP}” variable any where in value for OTP as shown in the below screenshot.

Add a Textbox to enter OTP – Give Unique name “OTPInput” as shown in the below screenshot.

To verify OTP(Generated by “OTPGenerator” Class) – Drag and drop “Decision” element from Palette(Logic) – Give the name “OTP Validation”. On the window to check whether variable {!OTP} is equal to Screen Input element {!OTPInput}. If both the values is not same, then it means don’t allow user to login into Salesforce.

For invalid OTP add a screen to show error message – Drag and drop “Screen” element from Palette(User Interface) – Give the name “Invalid OTP”

Add a “Display Message” – Give the name “InvalidTitle” – With the value “Invalid OTP!” as shown in the below screenshot.

Enter the Login Flow Name, Select the flow, User license and Profile, It will look like the below screenshot.

Now its time to test the “Two Factor Authentication”. To test it follow the below instructions:

Login into Salesforce through User who have same profile that you have used in Login Flow, In my case it’s “Custom Standard User”. After Successful login you will receive an email, it will look like the below screenshot.

Enter OTP(One-time Password) onto the screen input field (i.e. OTP) and click on the Next Button, as shown in the below screenshot.

If Security Code is matched then you will redirect to Salesforce Home Page else it will display an error message as shown in the below screenshot.

Note : I will suggest to implement and test it in your Developer or Sandbox org, and then move it to Production.

Trigger.new : Returns a list of the new versions of the sObject records. Note that this sObject list is only available in insert and update triggers, and the records can only be modified in before triggers.

Trigger.old : Returns a list of the old versions of the sObject records. Note that this sObject list is only available in update and delete triggers.