To use our SDK with React Native, you only need to check the nativeEvent field from the WebViewMessageEvent, which contains data about the specific event. See the example below:
import { useEffect, useRef, useState } from "react";
import { Linking } from "react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
import { WebView, WebViewMessageEvent } from "react-native-webview";
const urlMapper = {
cert: {
sdkMobile: "https://sdk-mobile.cert.zerohash.com",
zeroHashAppsURL: "https://web-sdk.cert.zerohash.com",
},
prod: {
sdkMobile: "https://sdk-mobile.zerohash.com",
zeroHashAppsURL: "https://web-sdk.zerohash.com",
},
};
/**
* List of permissions used to request a JWT in the `client_auth_token` request
*/
const permissions = [
"crypto-buy",
"crypto-sell",
"crypto-withdrawals",
"crypto-payouts",
"fiat-deposits",
"fiat-withdrawals",
"fwc", // Fund
"onboarding",
"participant-profile",
"update-participant",
"crypto-account-link",
];
/**
* You can copy and paste a JWT on jwtToken for testing. You will need to
* implement a function to fetch the JWT from your backend and replace this variable.
* We have an example below using fetchJwt and setToken functions.
* */
const jwtToken = ``;
const App = () => {
const webViewRef = useRef<WebView>(null);
const [token, setToken] = useState<string>(jwtToken);
useEffect(() => {
fetchJwt();
}, []);
// Fetch JWT token from server
const fetchJwt = async () => {
const jwtPayload = {
// The participant code you want to request the JWT for.
participant_code: "<PARTICIPANT_CODE>",
// The permission required for your use-case, refer to Permissions for
// the allowed values
permissions: ["fwc"],
};
try {
const response = await fetch(`<API_URL_TO_FETCH_TOKEN>`, {
method: "POST",
body: JSON.stringify(jwtPayload),
});
const parsedResponse = await response.json();
setToken(parsedResponse.message.token);
} catch (e) {
console.error("could not fetch jwt", e);
}
};
// Open modal using injected JS script in webview
const openModal = () => {
// Replace "jwtToken" with "token" to use the token you got from your backend
webViewRef.current?.injectJavaScript(
`window.postMessage({ "type": "OPEN_MODAL", "payload": { "appIdentifier": "fund", "jwt": "${jwtToken}"}});true;`
);
};
const handleMessage = (event: WebViewMessageEvent) => {
try {
// Parse message from webview event data checking nativeEvent field
const parsedMessage = JSON.parse(event.nativeEvent.data);
console.log("Received message:", parsedMessage);
if (parsedMessage.type === "SDK_MOBILE_READY") {
console.log("SDK is ready, opening modal...");
openModal();
}
// Handle webview events
// Your code here...
} catch (e) {
alert(
`could not parse message: ${JSON.stringify(event.nativeEvent.data)}`
);
}
};
return (
<SafeAreaProvider>
<SafeAreaView style={{ flex: 1 }}>
<WebView
allowsInlineMediaPlayback={true}
ref={webViewRef}
onMessage={handleMessage}
source={{
// Double check the environment you are using and pick the correct URLs
// accordingly
uri: `${urlMapper.cert.sdkMobile}/v1?zeroHashAppsURL=${urlMapper.cert.zeroHashAppsURL}`,
}}
onNavigationStateChange={(event) => {
if (!event.url.startsWith(urlMapper.cert.sdkMobile)) {
webViewRef?.current.stopLoading();
Linking.openURL(event.url);
}
}}
/>
</SafeAreaView>
</SafeAreaProvider>
);
};
export default App;
Fiat Account link (Android)
For Android the experience should not require any changes and at this first phase the user will be sent to the external browser to complete the Application with Plaid, once he finishes that the user will be presented with a "Success" page asking him to return to the Native Application and continue the flow.
Fiat Account link specific (iOS ASWebAuthenticationSession)
Overview
This guide explains how to add special handling for Plaid authentication flows in your React Native app using ASWebAuthenticationSession. This provides a native iOS authentication experience and automatically closes when the flow completes.
What This Does
- Detects when users navigate to plaid.com URLs in your WebView
- Launches native iOS
ASWebAuthenticationSessioninstead of loading in WebView - Automatically closes the authentication session when it detects completion
- Provides better user experience with native iOS authentication UI
Implementation Steps for expo
import React, { useRef } from "react";
import { Platform } from "react-native";
import { WebView } from "react-native-webview";
import * as WebBrowser from "expo-web-browser";
const REDIRECT_URL = "zerohashapp://done";
// Call once to handle auth completion on app startup (iOS requirement)
WebBrowser.maybeCompleteAuthSession();
export default function PlaidWebView() {
const webViewRef = useRef(null);
const launchAuthSession = async (url: string) => {
try {
// openAuthSessionAsync opens the secure system browser (ASWebAuthenticationSession)
const result = await WebBrowser.openAuthSessionAsync(url, REDIRECT_URL);
} catch (e) {
console.warn("Auth session error", e);
}
};
return (
<WebView
ref={webViewRef}
source={{ uri: "https://sdk-mobile.zerohash.com/v1" }}
allowsInlineMediaPlayback
// Interception: The core logic
onShouldStartLoadWithRequest={(request) => {
const url = request.url || "";
// Check for iOS and Plaid URL patterns
if (Platform.OS === "ios" && url.includes("plaid.com")) {
// Prevent the WebView from loading the URL itself
launchAuthSession(url);
return false;
}
}}
/>
);
}
Even if you are not using Expo you should be able to adapt opening the ASWebAuthenticationSession in your own structure, note that this is just for iOS and Android users will be redirected to the external default browser when using this flow.
