fia-react
v0.2.0
Published
FIA React Native by Fazpass.
Readme
fia-react
FIA React Native by Fazpass. Visit the official website for more information about the product, and see the github documentation for more technical details.
Wraps the native FIA SDKs: Android com.fazpass:fia:1.2.7 and iOS FiaIOS ~> 1.2.5.
Installation
npm install fia-reactiOS setup
The iOS SDK stores state in an App Group, so this is required — initialize() needs the container id.
In Xcode, under Signing & Capabilities, add:
- App Groups — add a container named
group.YOUR_INVERTED_DOMAIN - iCloud — enable the Key-value storage service
For the MagicOtp and MagicLink auth types, add to Info.plist:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>whatsapp</string>
<string>whatsappbusiness</string>
</array>For MagicLink you must also add an Associated Domains capability (applinks:YOUR_DOMAIN), serve an
apple-app-site-association file from that domain, and forward the incoming link to the SDK from your
AppDelegate — without this the link never reaches FIA and validation never completes:
import FiaReact
override func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
FiaReactLinking.onMagicLink(userActivity: userActivity)
return super.application(application, continue: userActivity, restorationHandler: restorationHandler)
}Android setup
For the Miscall auth type, add to your AndroidManifest.xml and request at runtime:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />For the HE auth type, add to your <application> tag:
android:networkSecurityConfig="@xml/fia_network_security_rules"This will break Metro in debug builds unless you also do the following. Android ignores
android:usesCleartextTrafficwhenever a network security config is present, and FIA's config only permits cleartext for the Fazpass domains — notlocalhost. Your debug app then cannot reach the Metro dev server, and fails with a misleadingUnable to load scripterror.Fix it by giving debug builds their own config that keeps FIA's domains and adds Metro's. Create
android/app/src/debug/res/xml/debug_network_security_config.xml:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <!-- Metro: localhost via `adb reverse`, 10.0.2.2 on the emulator. --> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="false">localhost</domain> <domain includeSubdomains="false">10.0.2.2</domain> </domain-config> <!-- Copied from the FIA SDK's rules, needed for Header Enrichment. --> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">verify.klikaman.online</domain> <domain includeSubdomains="true">api.fazpass.com</domain> <domain includeSubdomains="true">openapi.smartfren.com</domain> <trust-anchors> <certificates src="system" /> <certificates src="user" /> </trust-anchors> </domain-config> </network-security-config>and point debug builds at it in
android/app/src/debug/AndroidManifest.xml:<application android:networkSecurityConfig="@xml/debug_network_security_config" tools:replace="android:networkSecurityConfig" />See
example/android/app/src/debug/for a working copy.
For the MagicLink auth type, declare the SDK's activity inside <application> (and serve
assetlinks.json from your domain):
<activity
android:name="com.fazpass.fia.activities.magiclink.MagicLinkActivity"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="YOUR_DOMAIN" android:scheme="https" />
</intent-filter>
</activity>Usage
import FIA, { OtpPromise, OtpAuthType, OtpMagicRedirect, FiaErrorType } from 'fia-react';
// Initialize once, before anything else.
// appGroupId is required on iOS and ignored on Android.
FIA.initialize('MERCHANT_KEY', 'MERCHANT_APP_ID', 'group.com.example.app');
// Request an OTP. Use the method matching your use case:
// login(), register(), transaction() or forgetPassword().
let otpPromise: OtpPromise;
FIA.otp().login('PHONE', (promise) => {
if (promise.hasException) {
console.error(promise.error?.type, promise.error?.message);
return;
}
if (promise.isBlocked) {
// The user failed verification too many times and is temporarily blocked.
return;
}
otpPromise = promise;
});otpPromise.authType tells you how the user is being verified. Handle all of them:
switch (otpPromise.authType) {
case OtpAuthType.He:
// Nothing to input — just validate.
otpPromise.validateHE(onError, onValidated);
break;
case OtpAuthType.SMS:
case OtpAuthType.Whatsapp:
case OtpAuthType.Voice:
// Ask the user for the code (otpPromise.digitCount digits), then:
otpPromise.validate('USER_INPUT', onError, onValidated);
break;
case OtpAuthType.Miscall:
// The user types the last `digitCount` digits of the caller's number.
// On Android you can read them automatically instead:
otpPromise.listenToMiscall(onError, (otp) => {
otpPromise.validate(otp, onError, onValidated);
});
break;
case OtpAuthType.MagicOtp:
// Sends the user to WhatsApp; they come back with a code you then validate().
otpPromise.launchWhatsappForMagicOtp(onError, () => {
// show an input, then otpPromise.validate(...)
});
break;
case OtpAuthType.MagicLink:
// Sends the user to WhatsApp; they tap a link and validation completes on its own.
otpPromise.launchWhatsappForMagicLink(onError, onValidated);
break;
}When you're done with a promise, free it:
otpPromise.clean();A validated OTP does not by itself mean the user is verified. Check the verified status server-side using
otpPromise.transactionId— see the server documentation.
Options
login, register, transaction and forgetPassword all take an optional third argument:
FIA.otp().login('PHONE', callback, {
// Forwarded to the FIA backend with the request.
additionalInfo: { 'url': 'https://example.com' },
// Which WhatsApp app to open for MagicOtp / MagicLink. Defaults to Auto.
magicRedirect: OtpMagicRedirect.WhatsappBusiness,
});Errors
Every error callback receives a FiaError with a type (FiaErrorType) and a message:
otpPromise.validate('123456', (error) => {
if (error.type === FiaErrorType.VerificationFailed) {
// wrong or expired code
}
}, onValidated);Pro-features
FIA.setFeatures({
withLocation: true,
withOtpSpammingFunction: true,
withBiometricPopup: true,
biometricMessage: 'Confirm it is you',
withAccountTakeoverFunction: true,
userIdentifier: 'user-123',
withPromoAbuseFunction: true,
promoIds: ['PROMO_1'],
// Android only — the iOS SDK does not implement these:
withVpn: true,
withSimNumbersAndOperators: true,
withAppTamperingFunction: true,
withSuspiciousAppFunction: true,
});Platform differences
| | Android | iOS |
|---|---|---|
| initialize() appGroupId | ignored | required |
| listenToMiscall() | supported | no-op — iOS cannot read the caller's number |
| withVpn, withSimNumbersAndOperators, withAppTamperingFunction, withSuspiciousAppFunction | supported | ignored |
| MagicLink | manifest entry | FiaReactLinking.onMagicLink in AppDelegate |
