#firebase #recaptcha #integration #customelement #wixfirebase #signin #sms #OTP
Here is a write-up on how to integrate firebase authentication in wix
Firebase authentication provides solution for phone/email/social(fb,google,twitter etc.,) and more
Here I have documented the phone authentication mechanism.
Note: This solution is only for authenticating / validating a phone number via SMS using a one time password. This is not a free SMS solution.
Firebase phone authentication is free for up to 10k authentication per month.
Typical use case scenario:
user keys in phone number in your website → website initiates firebase authentication → an SMS is sent to the user’s phone number with an otp → user enters the otp in your website → website requests firebase to authenticate/validate → firebase returns validation result → website does it’s thing based on the result.
In the background firebase uses recaptcha, so at times, user may be required to solve a recaptcha challenge.
Pre-requisites:
- Setup a firebase project, details in the link below :
https://firebase.google.com/docs/auth/web/phone-auth
- Once you have created project and enabled phone authentication, you can
- setup test numbers
- setup authorised domains
- setup template messages
- Firebase/auth NPM module - add the firebase npm module or just the firebase/auth npm module based on your requirements.
Setup in wix
You could implement this whole solution as a custom element, or use a combination of velo + custom element. I have used the latter.
High level steps:
-
custom element
- create a button, which is required for firebase as a recaptcha container (I have made this button invisible and programatically triggered the click event) - use the attribute changed callback to handle each of the following * initialise firebase and setup recaptcha * send sms and render the recaptcha verifier * validate code 2. Page code - entirely upto you on how you want to implement this, as the meat of the matter is in the custom element code - I have just created elements for invoking the attribute changed callback as mentioned above
custom element code
import app from 'public/firebase_init.js'
import firebase from 'firebase/app';
import 'firebase/auth';
const createButton = () => {
const buttonElement = document.createElement('Button');
buttonElement.innerHTML = "button";
buttonElement.id = 'send-sms-button';
buttonElement.style.display = "none";
return buttonElement;
}
const getView = () => {
// the window object
return document.defaultView;
}
const getDoc = () => {
return document;
}
class MobileAuthenticatorCustomElement extends HTMLElement {
constructor() {
super();
this.authInstance = app.auth();
this.DOCUMENT = getDoc();
this.DEFAULT_VIEW = getView();
this.triggersmsbutton = createButton();
this.appendChild(this.triggersmsbutton);
this.phoneNumber = undefined;
app.auth().useDeviceLanguage();
}
static get observedAttributes() {
return ['setupcaptcha', 'sendauthsms', 'validatecode'];
}
connectedCallback() {
}
attributeChangedCallback(name, oldValue, newValue) { // is invoked when one of the custom element's attributes is added, removed, or changed
console.log("Attribute changed call back name:", name, " old val:", oldValue, " new val:", newValue);
if (name === "setupcaptcha") {
if (this.DEFAULT_VIEW !== undefined) {
if (!this.DEFAULT_VIEW.recaptchaVerifier) {
this.DEFAULT_VIEW.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('send-sms-button', {
'size': 'invisible',
'callback': () => {
this.onSendSmsButtonClick();
}
});
}
} else {
this.DEFAULT_VIEW = getView();
if (!this.DEFAULT_VIEW.recaptchaVerifier) {
this.DEFAULT_VIEW.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('send-sms-button', {
'size': 'invisible',
'callback': () => {
this.onSendSmsButtonClick();
}
});
}
}
} else if (name === "sendauthsms") {
this.phoneNumber = newValue;
this.DEFAULT_VIEW.recaptchaVerifier.render()
.then((widgetId) => {
this.DEFAULT_VIEW.recaptchaWidgetId = widgetId;
this.DOCUMENT.getElementById("send-sms-button").click()
})
.catch((err) => (console.log("captcha error ", err)));
} else if (name === "validatecode") {
const code = newValue;
this.confirmationResult.confirm(code).then((result) => {
console.log("Code authentication result ", result);
this.dispatchEvent(new CustomEvent("authenticated", {}))
this.confirmationResult = null;
this.resetReCaptcha();
}).catch((error) => {
console.log("Code authentication error ", error);
this.dispatchEvent(new CustomEvent("notauthenticated", {}))
})
}
}
onSendSmsButtonClick() {
return new Promise((resolve, reject) => {
let appVerifier = this.DEFAULT_VIEW.recaptchaVerifier;
app.auth().signInWithPhoneNumber(this.phoneNumber, appVerifier).then((confirmationResult) => {
console.log("Confirmation result ", confirmationResult);
this.confirmationResult = confirmationResult;
this.dispatchEvent(new CustomEvent("smssent", {}))
resolve(confirmationResult);
}).catch((confirmationErr) => {
console.log("Confirmation err ", confirmationErr);
this.dispatchEvent(new CustomEvent("smsnotsent", {}))
reject(confirmationErr);
})
})
}
resetReCaptcha() {
this.DEFAULT_VIEW.recaptchaVerifier.clear();
if (typeof grecaptcha !== 'undefined' &&
typeof this.DEFAULT_VIEW.recaptchaWidgetId !== 'undefined') {
grecaptcha.reset(this.DEFAULT_VIEW.recaptchaWidgetId);
}
}
}
customElements.define('mobile-authenticate-ce', MobileAuthenticatorCustomElement);
page code
$w.onReady(function () {
// TODO: write your page related code here…
$w(‘#mobileAuthCE’).on(‘smssent’, () => {
// do your actions to be performed once the SMS has been sent
});
$w(‘#mobileAuthCE’).on(‘smsnotsent’, () => {
// error handling in case SMS not sent
});
$w(‘#mobileAuthCE’).on(‘authenticated’, () => {
// actions to be performed on authentication success
});
$w(‘#mobileAuthCE’).on(‘notauthenticated’, () => {
// actions to be performed on authentication failure
});
});
export function setupCaptchaButton_click(event) {
$w(“#mobileAuthCE”).setAttribute(“setupcaptcha”, “null”);
}
export function sendSMSButton_click(event) {
// This function was added from the Properties & Events panel. To learn more, visit Velo: Working with the Properties & Events Panel | Help Center | Wix.com
// Add your code for this event here:
$w(“#mobileAuthCE”).setAttribute(“sendauthsms”, $
w(“#mobilenumberinput”).value);
}
export function checkCodeButton_click(event) {
$w(“#mobileAuthCE”).setAttribute(“validatecode”, $w(“#mobileverificationcodeinput35”).value);
}
screen shot of SMS received with otp.