Two-factor authentication using LWC

Use Case: In this blog we are going take the use case to build "Two-factor authentication (EMAIL)" using Lightning Web Component.

This use case is going to be helpful to place an extra layer of security, especially when when we try to expose Salesforce sensitive data using Public Sites (or) Communities.

Code Components: Below we are going to use 3 main code components to implement Two-factor email authentication.

1. CommonUtility.cls : Apex class that has two methods. One method to generate unique 6 digit code using crypto class and another method to generate single email message and dispatch email.


public with sharing class CommonUtility {
    @AuraEnabled(cacheable=true)
    // Method to send 6 digit two-factor email verification
    public static String twoFactorGen(String usrEmail) {
        String verCode = genUniqueCode(); // generate unique 6 digit code
    
        Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage(); // instantiate emailMessage
        message.toAddresses = new String[] { usrEmail }; // add userEmail to the list
            message.optOutPolicy = 'FILTER';
        message.subject = 'Two Factor Authentication Email Verification Code'; // email subject        
        message.plainTextBody = 'Please use ' + verCode + ' to verify ' + usrEmail + ' - Thanks!'; // email body
        message.setOrgWideEmailAddressId('0D28A0000008QBgSAM');
        
        Messaging.SingleEmailMessage[] messages = 
            new List<Messaging.SingleEmailMessage> {message};
                Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);
        return results[0].success ? verCode : 'undefined';
    }
    
    // Method to generate 6 digit unique code
    private static String genUniqueCode() {
        Blob b = Crypto.GenerateAESKey(128); // use crypto class to generate key
        String s = EncodingUtil.ConvertTohex(b); // convert blob to hex
        return s.subString(0,6).toUpperCase();
    }
}

2. twoFactorEmailAuth.html : LWC html that initially has an email input field on component load to allow user to input valid email address and request code by clicking on "Get Code" button. This will generate unique code and further expose text field for user to input email generated Two-factor verification code.


<template>
    <lightning-card class="slds-theme_shade slds-theme_alert-texture" title="User Authentication">
        <!-- to allow user to input email -->
        <template if:true={enableEmailInput}>
            Email Input: {userEmail}
            <lightning-input type="email" placeholder="Enter valid email" value={userEmail} onchange={userInput}>
            </lightning-input><br />
            <lightning-button class="slds-align_absolute-center" label={btnLabel} variant="brand"
                onclick={validateClick}>
            </lightning-button><br />
            <!-- to allow user to input verification code -->
            <template if:true={enableVerify}>
                <lightning-input type="text" placeholder="Enter code here" value={userCode} onchange={inputCode}>
                </lightning-input>
                <lightning-button class="slds-align_absolute-center" label="Validate" variant="brand"
                    onclick={validateCode}>
                </lightning-button>
            </template>
        </template>
        <!-- to navigate user to home page -->
        <template if:false={enableEmailInput}>
            <div
                class="slds-text-heading_medium slds-align_absolute-center slds-text-color_success slds-text-title_bold">
                User is successfully validation!</div>
        </template>
    </lightning-card>
</template>

3. twoFactorEmailAuth.js : LWC javascript to handle all user input and button click actions to validate inputs, generate unique code by calling apex controller method, and finally navigate user to Home Page upon successful validation.

import { LightningElement, track } from 'lwc';
import twoFactorGen from "@salesforce/apex/CommonUtility.twoFactorGen";
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { NavigationMixin } from 'lightning/navigation';

export default class EmailTwoFactorAuthentication extends NavigationMixin(LightningElement) {
    // local variables to track data values
    @track userEmail;
    @track tempCode;
    @track userCode;
    @track btnLabel = 'Get Code';
    @track enableEmailInput = true;
    @track enableVerify;
    @track tabName = 'Home';

    url;
    connectedCallback() {
        this.accountHomePageRef = {
            type: 'standard__namedPage',
            attributes: {
                pageName: 'home'
            }
        };
        this[NavigationMixin.GenerateUrl](this.accountHomePageRef)
            .then(url => this.url = url);
    }

    // track user input email
    userInput(event) {
        this.userEmail = event.target.value;
    }

    // track user input verfication code
    inputCode(event) {
        this.userCode = event.target.value;
    }

    // process user click to generate email two-factor auth code
    validateClick() {
        // check for null values
        if (this.userEmail != null && this.userEmail != undefined) {
            this.genCode(); // local method to call apex
        } else {
            // show exception toast notification
            this.showNotification('Error', 'Email address is required!', 'error');
        }
    }

    // validate user input two-factor code
    validateCode() {
        if (this.tempCode === this.userCode) {
            this.showNotification('Information', 'Input code is successfully validatated!', 'info');
            this.enableEmailInput = false;
            alert('Your are being navigated to Home Page!');
            this.navigateNext();// navigate user to home page
        } else {
            this.showNotification('Warning', 'Input code is not valid, please make sure to use correct code!', 'warning');
        }
    }

    // method to call apex that generates two-factor verification code
    genCode() {
        //alert("User Input Email: " + this.userEmail);
        twoFactorGen({ usrEmail: this.userEmail })
            .then(result => {
                if (result === 'undefined') {
                    this.showNotification('Error', 'Error generating Two-Fator verification code: ' + result, 'error');
                } else {
                    this.showNotification('Success', 'Two-Factor code is successfully sent!', 'success');
                    this.tempCode = result;
                    this.enableVerify = true;
                }
            })
            .catch(error => {
                this.showNotification('Error', 'Exception Occured: ' + JSON.stringify(error), 'error');
            })
        this.btnLabel = 'Resend Code';
    }

    // method to invoke toast message
    showNotification(title, message, variant) {
        const evt = new ShowToastEvent({
            title: title,
            message: message,
            variant: variant,
        });
        this.dispatchEvent(evt);
    }

    // navigate user to home page
    navigateNext() {
        this[NavigationMixin.Navigate](this.accountHomePageRef);
    }
}

We are going to add above LWC to a custom Tab, in order to view on how it works in practical. Make sure to update twoFactorEmailAuth.js-meta.xml file with below, so that LWC is exposed for use in custom tabs.
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>

DEMO:

Few Points to Note:
  • The above LWC has Experienced Page Time (EPT) of ~0.38 s as it is rendering most of the input/button actions conditionally.
  • Here in my case, We are using an external email address to send Two-factor code so that might count towards org "SingleEmailMessage" limits. Keeping an eye on that limit is important or we can optimize this by using TargetObjectId instead of an actual email address.
  • Comments

    1. Nice article!
      I found many useful information in your blog, it was awesome to read,thanks for sharing this great content, keep sharing..
      Salesforce Consulting Services

      ReplyDelete
    2. Buy high quality Grade A counterfeit money Real Passports, Visas, Driver's License ,ID CARDS, Marriage certificates, Diplomas, Birth Certificates, Credit cards, Utility bills, Social Security cards, Resident permits, Death certificates, Seaman cards, e.t.c Text/WhatsApp +17202488130 ( lifiben@gmail.com )


      high quality undetectable counterfeit banknotes for sale
      buy high quality counterfeit money online
      buy undetectable counterfeit money online cheap
      buy 100% undetectable counterfeit money uk
      high quality counterfeit money for sale
      counterfeit money supplier
      best place to buy counterfeit money
      buy counterfeit money online
      Text/WhatsApp +17202488130 ( lifiben@gmail.com )

      ReplyDelete
    3. Buy Viagra super p-force online is commonly used for human to stimulate erection in body. Its known as Sildenafil commonly named Viagra.

      ReplyDelete
    4. Do you want a painkiller without prescription that you can use for moderate to severe pain? Then Buy Tramadol Online is an excellent choice. This painkiller is so powerful that it is used to treat post-operative pain, pain caused by illnesses and other severe pain problems.

      ReplyDelete
    5. Discover the golden richness of UGM Village Wala A2 Desi Cow Ghee (250gm) – now on sale Made using the authentic bilona method from indigenous Indian cows, this lactose-free, 100% pure and natural ghee is a nutritional powerhouse packed with vitamins A, D, E, and K. FSSAI certified (12723028000065) with a 12-month shelf life, it’s vegetarian and perfect for digestion, immunity boost, skin health, and versatile cooking – from sautéing veggies to baking desserts.

      https://www.ugmstore.com/product/village-wala-a2-desi-cow-ghee/

      ReplyDelete

    Post a Comment

    Popular posts from this blog

    Lightning Data Service - Salesforce new Apex alternative - Part 2

    Using JavaScript Promises in Lightning Components