Configure client apps for one-time passcodes
Select your platform to discover how to configure your client application to use one-time passcodes during an authentication flow.
Configure an Android app to use one-time passcodes
Your app must handle the DeviceRegistrationCollector and DeviceAuthenticationCollector collector types that DaVinci sends. These contain details of the available one-time passcode delivery methods.
|
Learn more about setting up an app to receive collectors in the Tutorials. |
Loop through the collectors returned by DaVinci, ensuring you handle the one-time passcode collectors:
continueNode.collectors.forEach {
when (it) {
// Other collectors here...
is DeviceRegistrationCollector -> {
// Compose to display DeviceRegistrationCollector
DeviceRegistration(it, onNext)
}
is DeviceAuthenticationCollector -> {
// Compose to display DeviceAuthenticationCollector
DeviceAuthentication(it, onNext)
}
// Compose to display PhoneNumberCollector
is PhoneNumberCollector -> PhoneNumber (it, onNodeUpdated)
}
}
After collecting the data for a node you can proceed to the next node in the flow by calling the next() method on your current node object.
Learn more about node.next() in Continuing a DaVinci flow in the Android deep-dive tutorial.
Sample collector view files:
Configure an iOS app to use one-time passcodes
Your app must handle the DeviceRegistrationCollector and DeviceAuthenticationCollector collector types that DaVinci sends. These contain details of the available one-time passcode delivery methods.
|
Learn more about setting up an app to receive collectors in the Tutorials. |
Loop through the collectors returned by DaVinci, ensuring you handle the one-time passcode collectors:
ForEach(continueNode.collectors , id: \.id) { collector in
switch collector {
// Other collectors here...
case is DeviceRegistrationCollector:
if let deviceRegistrationCollector = collector as? DeviceRegistrationCollector {
DeviceRegistrationView(field: deviceRegistrationCollector, onNext: onNext)
}
case is DeviceAuthenticationCollector:
if let deviceAuthenticationCollector = collector as? DeviceAuthenticationCollector {
DeviceAuthenticationView(field: deviceAuthenticationCollector, onNext: onNext)
}
case is PhoneNumberCollector:
if let phoneNumberCollector = collector as? PhoneNumberCollector {
PhoneNumberView(field: phoneNumberCollector, onNodeUpdated: onNodeUpdated)
}
default:
EmptyView()
}
}
After collecting the data for a node you can proceed to the next node in the flow by calling the next() method on your current node object.
Learn more about node.next() in Continuing a DaVinci flow in the iOS deep-dive tutorial.
Sample collector view files:
Configure a JavaScript app to use one-time passcodes
Your app must handle the DeviceRegistrationCollector and DeviceAuthenticationCollector collector types that DaVinci sends. These contain details of the available one-time passcode delivery methods.
You might also need to handle PhoneNumberCollector collectors, if the user chooses Voice or SMS as their MFA method, for example.
|
Learn more about setting up an app to receive collectors in the Tutorials. |
Loop through the collectors returned by DaVinci, ensuring you handle the one-time passcode collectors:
const collectors = davinciClient.getCollectors();
collectors.forEach((collector) => {
if (
collector.type === 'DeviceRegistrationCollector' ||
collector.type === 'DeviceAuthenticationCollector'
) {
deviceComponent(
collector, // Object of the collector
davinciClient.update(collector), // Return updater for collector
);
} else if (collector.type === 'PhoneNumberCollector') {
phoneNumberComponent(
collector, // Object of the collector
davinciClient.update(collector), // Return updater for collector
);
}
});
In this example, a deviceComponent or phoneNumberComponent component handles rendering the relevant user interface. Pass the selected option into the updater() method:
deviceComponent file to render OTP selectionexport default function deviceComponent(
collector: DeviceRegistrationCollector | DeviceAuthenticationCollector,
updater: Updater,
) {
const groupLabel = collector.output.label || 'Select an option';
// Bind to options to handle user selection
function eventHandler(event) {
const selectedValue = // get value from event's target element
updater(selectedValue);
}
// Iterate over the options and render each
for (const option of collector.output.options) {
const elementLabel = option.label;
const elementValue = option.value;
// Render each element to DOM
}
}
phoneNumberComponent file to render OTP selectionexport default function phoneNumberComponent(
collector: PhoneNumberCollector,
updater: Updater,
) {
const phoneLabel = collector.output.label || 'Phone Number';
// Get default or existing values
const countryCodeValue = collector.output.value.countryCode;
const phoneNumberValue = collector.output.value.phoneNumber;
// This just uses a mutable object for simplicity
let phoneObject = {
countryCode: countryCodeValue,
phoneNumber: phoneNumberValue,
};
// Add change event listener to country code select
function handleCountryCodeEvent(event) {
const selectedValue = // get value from event's target element
// Mutate object then pass to updater
phoneNumber = { ...phoneObject, countryCode: selectedValue };
updater(phoneNumber);
}
// Add change event listener to phone number input
function handlePhoneNumberEvent(event) {
const selectedValue = // get value from event's target element
// Mutate object then pass to updater
phoneNumber = { ...phoneObject, phoneNumber: selectedValue };
updater(phoneNumber);
}
// Render both country code select and phone number input
}