React Native

Add the Trustly UI to React Native mobile apps

The Trustly Lightbox Javascript library allows you to quickly build a bank authorization workflow in your React Native app. Integrate the Trustly Lightbox to retrieve bank authorization data that can be used with other Trustly APIs.

💻

Example App

To use an example project for testing and learning, see the React Native Example in Github.

OAuth Configuration

Banks that use OAuth login pages often have strict security policies which prohibit access to their login urls from WebViews. Trustly client libraries include functionality that simplifies OAuth handling. For more information about using OAuth login authorization flows with the Trustly Lightbox, see the OAuth Guide

Add the React Native Components

  1. Run the following command to add react-native-webview to your application or alternative WebView package:

    npm install react-native-webview --save
  2. Run the following command to add the react-native-inappbrowser component to your application or alternative in-app browser package:

    npm install react-native-inappbrowser-reborn --save
  3. Configure a deep link for your application. See the React Native linking documentation. Typically, the format for a deep link or URL scheme in your application is: my_app://.

Launch the Lightbox

The Lightbox is launched by using the establishData variable. The variable must include a metadata object with the following properties:

  • urlScheme - the URL you want the user to return to after completing an OAuth or “App-to-App” user flow. For example, my_app:// or my_app://path/success.
  • integrationContext - one of InAppBrowser or InAppBrowserNotify. InAppBrowserNotify posts a message to the WebView element and is recommended by Trustly. InAppBrowser triggers a window.open event using a target url that is opened in a secure in-app browser.
🚧

Multi-platform Users

If your web page containing the Lightbox serves both web browser users and mobile app users, the default Lightbox web browser behavior does not function when the integrationContext property is included. Trustly recommends adding the metadata properties dynamically. See the Trustly WebView Example app for an example implementation.

In the following example, a number of the required establishData variable properties are omitted for simplicity. For a complete list of the required properties, see Establish Data.

const establishData = {
  accessId: 'YOUR_ACCESS_ID',
  merchantId: 'YOUR_MERCHANT_ID',
  metadata: {
    urlScheme: "YOUR_APP://",
    integrationContext: "InAppBrowserNotify",
  }
};

Render the Lightbox in a WebView

You can open the Lightbox in a separately hosted web page or raw html. The following example uses the react-native-webview package to open the myapp.com/checkout URL where the Trustly Lightbox is rendered:

import { WebView } from 'react-native-webview';

class TrustlyWebview extends Component () {
  render(){
    return (
      <WebView
        source={{ uri: 'https://myapp.com/checkout' }}
        javaScriptEnabled={true}
        startInLoadingState
      />);
  }  
}

Note: For this package, the property javaScriptEnabled={true} must be passed to allow the Lightbox to communicate with your app’s WebView.

Set up Window Message Listener

Errors can occur when a user selects an OAuth-enabled bank and then selects their login URL within the WebView. You can use the window.ReactNativeWebview.postMessage method to simplify error handling in React Native apps.

  1. Add the window.ReactNativeWebview.postMessage method to inject a listener in the WebView. For example:

    import { WebView } from 'react-native-webview';
    
    const postMessageForOauth = `
      window.addEventListener(
      "message",
      function (event) {
        var data = (event || {}).data || {}
        window.ReactNativeWebView.postMessage(event.data);
      },
      false
      );
    `;
    
    class TrustlyWebview extends Component () {
      render(){
        return (
          <WebView
            source={{ uri: 'https://myapp.com/checkout' }}
            javaScriptEnabled={true}
            injectedJavaScript={postMessageForOauth}
            startInLoadingState
          />);
      }  
    }
  2. Configure your app to listen for these messages. The following is an example of an OAuth login window message:

    {
        "nativeEvent": {
            "canGoBack": true,
            "canGoForward": false,
            "data": "PayWithMyBank.ExternalBrowserIntegration|open|https://sandbox.paywithmybank.com/step/oauth/login/1024436793?ts=1691778330867&lbid=1691778325518|oauth:_FIOAuthWindow",
            "loading": false,
            "target": 3,
            "title": "Trustly",
            "url": "about:blank"
        }
    }
  3. Create a message handler function to filter and verify the messages your application receives and then pass them to the onMessage property of the WebView component. For example:

    import { WebView } from 'react-native-webview';
    
    const postMessageForOauth = `
      window.addEventListener(
      "message",
      function (event) {
        var data = (event || {}).data || {}
        window.ReactNativeWebView.postMessage(event.data);
      },
      false
      );
    `;
    
      messageHandler = (message: any) => {
        const data = message.nativeEvent.data
        var [command, ...params] = data.split("|")
        
        // check for correct message content
        if(command.includes("ExternalBrowserIntegration")) {
          var messageUrl = params[1]
          // user selected an OAuth bank
          console.log("Trustly URL", messageUrl)
        }
      }
    
    class TrustlyWebview extends Component () {
      render(){
        return (
          <WebView
            source={{ uri: 'https://myapp.com/checkout' }}
            javaScriptEnabled={true}
            injectedJavaScript={postMessageForOauth}
            startInLoadingState
            onMessage={this.messageHandler}
          />);
      }  
    }
🚧

Integration Context

If you set the IntegrationContext property to InAppBrowser, use the onNavigationStateChange property instead of onMessage and use navigationChangeHandler instead of the messageHandler function.

📘

Messages and OAuth Login URLs

The example only verifies an expected portion of the data property of the message. If additional verification or filtering is required, consider adding the following URLs in the data property of the message:

Sandbox
www.sandbox.paywithmybank.com/step/oauth/login/{transactionId} https://sandbox.paywithmybank.com/step/oauth/login/{transactionId} www.sandbox.trustly.one/step/oauth/login/{transactionId} https://sandbox.trustly.one/step/oauth/login/{transactionId}

Production
www.paywithmybank.com/step/oauth/login/{transactionId} https://paywithmybank.com/step/oauth/login/{transactionId} www.trustly.one/step/oauth/login/{transactionId} https://trustly.one/step/oauth/login/{transactionId}

Additionally, an epoch timestamp is attached as a query parameter. For example:

www.trustly.one/step/oauth/login/{transactionId}?ts=1519211809934

Open the External Link

Many banks consider WebViews an insecure method for accepting and authenticating user credentials. Following the completion of this step, when a customer opens the Trustly Lightbox and selects an OAuth-required Bank, a secure in-app-browser layer opens over the Lightbox. This layer contains information about the selected bank and a button that a customer can select to authenticate with their bank’s mobile app or through the bank’s OAuth login web page. After a customer is successfully authenticated, they are directed back to your app.

There are several packages that provide abstractions for the iOS and Android APIs. The following example uses the react-native-inappbrowser-reborn package:

import { InAppBrowser } from 'react-native-inappbrowser-reborn';

class TrustlyWebview extends Component () {
  
  openOAuthLink = async link => {
    try {
      await InAppBrowser.openAuth(link, '', { modalPresentationStyle: "fullscreen"})
        .then(response => {
        // handle user action in auth session
        
      });
    } catch (err) {
      console.log(err);
    }
  }
  
  messageHandler = (message: any) => {
    const data = message.nativeEvent.data
    var [command, ...params] = data.split("|")
    
    // check for correct message content
    if(command.includes("ExternalBrowserIntegration")) {
      var messageUrl = params[1]
      // user selected an OAuth bank
      console.log("Trustly URL", messageUrl)
      this.openOAuthLink(messageUrl)
    }
  }
  
  // render function ommitted for brevity

}

This example shows a simplified InAppBrowser function. For more information, see the documentation and the API specification for your preferred in-app browser package

Return to the Lightbox

To complete the authentication process, the InAppBrowser.openAuth() function is used to handle the Promise and notify the Trustly Lightbox that the customer has returned from their OAuth session. Within this callback, you add a function to inject the JavaScript that calls the Trustly.proceedToChooseAccount() function in the WebView. For example:

import { InAppBrowser } from 'react-native-inappbrowser-reborn';

class TrustlyWebview extends Component () {
  
  const postMessageForOauth = `
    window.addEventListener(
    "message",
    function (event) {
      var data = (event || {}).data || {}
      window.ReactNativeWebView.postMessage(event.data);
    },
    false
    );
  `;

	openOAuthLink = async link => {
	  try {
			await InAppBrowser.openAuth(link, '', { modalPresentationStyle: "fullscreen"})
				.then(response => {
					if (response.type === 'success') {
						// notify Trustly object of user return
			      this.webview.injectJavaScript('window.Trustly.proceedToChooseAccount();');
			    } else {
						console.log(response);
				});
	  } catch (err) {
	    console.log(err);
	  }
	}
	
	//messageHandler ommitted for brevity

	render(){
		return (
	    <WebView 
	      source={{ uri: 'https://myapp.com/checkout' }}
	      javaScriptEnabled={true}
        injectedJavaScript={postMessageForOauth}
	      startInLoadingState
        onMessage={this.messageHandler}
	    />);
	}  
}