Add Native Support for Phone/OTP Login in Custom UI
The AADB2CBase.custom widget provides an excellent developer experience for creating native email/password authentication flows. However, this simplicity does not extend to phone and OTP-based login.
To implement a custom UI for phone login, the developer must manually write JavaScript to interact with the webview's HTML. This includes parsing <select> elements for country codes, handling OTP-specific alert elements, and programmatically selecting <option> tags. This approach is less robust and requires more boilerplate than the existing email/password flow.
To create a more consistent and streamlined developer experience, I propose enhancing the custom UI functionality with built-in support for phone and OTP flows. This would involve:
-
Extending
HtmlParseType: Introduce new types to natively recognize phone-related HTML elements, such asHtmlParseType.selectfor country code dropdowns. -
Enhancing
ActionController:- Add a new method to the
controllerthat allows selecting a dropdown<option>by its index. This is crucial because Azure B2C's HTML can contain duplicatevalueattributes for different country codes, making selection by value unreliable. - Provide a way to natively listen for and handle common phone/OTP validation alerts (e.g.,
claimVerificationServerError).
- Add a new method to the
This would empower developers to build custom phone/OTP UIs with the same level of ease as the current email/password implementation, abstracting away the underlying JavaScript.
Below are examples of the manual JavaScript execution currently required, which this feature would ideally eliminate.
Example 1: Manually parsing country codes from a <select> element
final result = await actionController.runJavaScriptReturningResult('''
(() => {
const select = document.getElementById('countryCode');
if (!select) return '[]';
const options = Array.from(select.options)
.map((option, originalIndex) => ({
index: originalIndex,
code: option.value,
name: option.text,
isSelected: option.selected,
disabled: option.disabled
}))
.filter(option => !option.disabled);
return JSON.stringify(options);
})();
''');
Example 2: Manually listening for Phone Input and OTP error alerts
await actionController.getCustomAlerts([
FlutterJsCustomAlert(
type: JsDocumentType.elementById,
code: 'claimVerificationServerError',
conditions: {'aria-hidden': 'false'},
),
FlutterJsCustomAlert(
type: JsDocumentType.byClassName,
code: '.verificationErrorText.error',
conditions: {'aria-hidden': 'false'},
),
]);
Example 3: Manually selecting a country code by index
await actionController.runJavaScript(
"document.getElementById('countryCode').selectedIndex = ${country.index};",
);
By adding first-class support for these interactions, the package would become significantly more powerful and easier to use for a common authentication scenario.