Webview

Quickstart guide for adding Trustly UI to multi-platform apps via webview

⚠️

Webview Notice

Trustly does not recommend using Webview to integrate the Trustly UI within a mobile app. To deliver a superior user experience and minimize future maintenance requirements, consider using Trustly's official iOS and Android SDKs.

Summary

For applications that use a multi-platform architecture, in which a web-based checkout experience is embedded in a mobile app via a Webview, special attention must be paid to ensure the Lightbox is integrated successfully. In addition to this guide, see our official Trustly Webview Example application.

OAuth Between Mobile Apps

Some banks, such as Chase and Bank of America, require OAuth login authorization flows in which users are directed to the bank's login page or mobile app to login and authorize before being redirected back to your application.

See the OAuth Guide for more background information on OAuth.

In a traditional web browser the OAuth flow is handled by default as web browser simply opens a new window, then closes that window and returns the user to the initial window. However, a Webview within a mobile app does not have the same functionality and abilities, therefore additional steps must be taken to handle the workflow.

Integration Steps

📘

Prerequisites

The mobile application rendering the webview must have at least one configured universal link (or deep link) in order to properly return users from OAuth login back to the mobile application. Learn more at the following links about configuring universal links in iOS and deep links in Android.

With that background, the following steps will guide you to successfully integrate the Trustly Lightbox from a Webview inside your mobile app. There are primarily four steps to building this integration successfully:

👍

Checklist

  1. Launch the Lightbox
  2. Listen for navigation events inside the Lightbox
  3. Open the Trustly OAuth login URL
  4. Notify the Lightbox to proceed on user return

Note: This guide uses Swift examples, but the patterns and principles can be applied to any platform, language or framework. For complete examples in both iOS and Android (Kotlin) see this example app repository.

Launching the Lightbox in a Webview

Regardless of how the Trustly JavaScript is loaded into the HTML which is rendered in the webview, your Trustly Access ID must be included in the URL that loads the Trustly Javascript.

<html>
	<head>
    ...
    <script src="https://{ENVIRONMENT}.trustly.one/start/scripts/trustly.js?accessId={yourAccessId}"></script>
    <title>Pay With Trustly</title>
  </head>
		...
</html>

In addition to the standard variables required to load the Lightbox, in order for OAuth flows to work correctly from a mobile app, the establishData passed into the Trustly Lightbox methods must include a metadata object with two key properties:

  1. urlScheme which is the URL you expect the user to return to after completing an OAuth or “App-to-App” user flow. e.g my_app://checkout/bank/oauth_success
  2. integrationContext which can be one of three valid strings, either InAppBrowser, InAppBrowserNotify or ExternalBrowser. In order for OAuth to work in the manner described in this guide, the string InAppBrowser must be provided.

Example:

let establishData = {
  accessId: 'YOUR_ACCESS_ID',
  merchantId: 'YOUR_MERCHANT_ID',
  ...
  metadata: {
    urlScheme: "YOUR_APP://SOME_RESOURCE",
    integrationContext: "InAppBrowser",
  }
};

// define options if needed
let trustlyOptions = {};

window.Trustly.establish(establishData, trustlyOptions)

With these properties included in the establishData object, the web page containing the Trustly Lightbox is ready to integrate with a webview in your mobile app.

🚧

Multi-platform Users

Note that the presence of the integrationContext="InAppBrowser will break the default web browser behavior of the Lightbox. If your web page containing the Trustly Lightbox serves both web browser users and mobile app users, the web page should add these metadata properties dynamically. A suggested approach to handle this is demonstrated in the Trustly Webview Example app.

The next item to consider is launching the webview in your mobile app. Make sure to add the preferences and configurations required to enable the webview and Lightbox web page to interact as in the example below:

import Foundation
import UIKit
import WebKit


class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {

	override func viewDidLoad() {
        super.viewDidLoad()
        
			// replace this url with the web page that is rendering the Trustly Lightbox (can be localhost for testing purposes)
        let url = URL(string: "https://myapp.com/pay-with-Trustly")!
        let reqApp = URLRequest(url: url);

        self.webView = WKWebView(
           frame: self.view.bounds,
           configuration: self.getWKWebViewConfiguration()
        )
				
				// allow navigation events in the webview
        webView.navigationDelegate = self
        webView.uiDelegate = self

				// load and render the url request defined above
        webView.load(reqApp)
        self.view.addSubview(self.webView)
    }

	// this function returns all the necessary configurations for Lightbox behavior
	private func getWKWebViewConfiguration() -> WKWebViewConfiguration {
      let userController = WKUserContentController()
      let configuration = WKWebViewConfiguration()
      let wkPreferences = WKPreferences()
      wkPreferences.javaScriptCanOpenWindowsAutomatically = true
      configuration.preferences = wkPreferences
      configuration.userContentController = userController
      return configuration
	}
}

With this simple webview rendering our web page and the appropriate metadata properties in your establishData, the Lightbox will load normally, but behave differently when a user selects an OAuth-required bank. The next steps describe how to handle these behaviors.

Listening for Navigation Events

When a user selects an OAuth-required bank, the Trustly Lightbox will trigger a window.open() function targeting a Trustly-hosted url, effectively continuing the user’s session in the Lightbox in an external window. As explained in the background section, a webview cannot simply open a new window the way a typical web browser could, so your app must handle that behavior directly. Without the step below, no window will open and the user will remain in the webview on the active Lightbox panel.

In order to open this url, your app must listen for navigation events inside the Trustly Lightbox.

Within your webview add a function and check for window navigation events to Trustly’s URL.

class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {

	private var webView: WKWebView!

	override func viewDidLoad() {
      super.viewDidLoad()
      
			...
      
      webView.load(reqApp)
      self.view.addSubview(self.webView)
  }

	private func getWKWebViewConfiguration() -> WKWebViewConfiguration {
      ...
	}

	// this function will run on any navigation event that happens inside the webview
	func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
			
			// Check that url is external and expected	
	    if navigationAction.targetFrame == nil, let url = navigationAction.request.url {
	      if url.description.lowercased().range(of: "/step/oauth/login") != nil {
				
					// this is where we will open the secure browser session
	          
	      }
	    }
	    return nil
	}
}

📘

OAuth Login URLs

The URL verification example above only verifies the expected url path variables for the Trustly Lightbox URL, if you'd like to implement more specific verification rules, be sure to account for URLs such as these:

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 will be attached as a query parameter as demonstrated below:

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

Now your app’s webview is prepared to handle the window.open event from within the Trustly Lightbox. The next step outlines the specifics of how the link should be opened.

Opening the External Link

At this point, it may seem appropriate to open the external url in a new webview. However, many banks do not consider webviews secure for the purposes of entering user credentials and creating an authenticated user session. Therefore, OAuth login pages must be opened in a secure in-app browser.

For iOS, the secure in-app browser class ASWebAuthenticationSession is preferred, however it was introduced in iOS 12 therefore your app may need to also support SFAuthenticationSession if it is available for earlier iOS versions.

For Android Chrome Custom Tabs provide similar capabilities.

Add a function like the example below to open a secure in-app browser:

import AuthenticationServices

...

private var webSession: ASWebAuthenticationSession!

...

private func buildASWebAuthenticationSession(url: URL, callbackURL: String){
  
		webSession = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURL)
		// add basic configurations
    webSession.prefersEphemeralWebBrowserSession = true
		// assign the ASWebAuthentication 
    webSession.presentationContextProvider = self
    webSession.start()
}

Before calling this function, notice the included parameter, callbackURL. This parameter provides the destination to redirect the user to when the authentication session is complete. The value of this parameter must be exactly the same as the urlScheme parameter that was passed into the establishData.metadata object when the Lightbox was launched.

import WebKit

...

class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {

	private var webView: WKWebView!

	override func viewDidLoad() {
      ...
      webView.load(URLRequest(url: URL(string: "YOUR_WEB_PAGE_WITH_TRUSTLY_JS")))
  }

	func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
			
			// Check that url is external and expected	
	    if navigationAction.targetFrame == nil, let url = navigationAction.request.url {
	      if url.description.lowercased().range(of: "http") != nil {
				
						// OPEN THE EXTERNAL URL
						if #available(iOS 13, *) {
		            self.buildASWebAuthenticationSession(url: url, callbackURL: "YOUR_APP://checkout/trustly/oauth_return")
		        } else {
							// handle iOS <12 with SFAuthenticationSession
						}
	          
	      }
	    }
	    return nil
	}

}

At this point, upon opening the Trustly Lightbox and selecting an OAuth-required Bank (e.g. Chase) the user will see a new secure in-app-browser layer open over the Lightbox containing information regarding the chose bank’s OAuth experience and a button prompting them to “Continue to {Bank Name}”.

And, upon clicking the link, the user will be able to authenticate with their bank’s mobile app or through the bank’s OAuth login web page. After a successful authentication, the user will be directed back to your app. However, the Trustly authorization process will not be complete until we handle the final step.

Return to the Lightbox

The final step is to listen for the user’s return and prompt Trustly to complete the authorization process. To do this, we only need to modify the buildASWebAuthenticationSession so that when the session is complete, the webview calls the proceedToChooseAccount() method which is built in to the Trustly Lightbox.

Add a completionHandler parameter as in this example below:

private func buildASWebAuthenticationSession(url: URL, callbackURL: String){
  
		webSession = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURL, completionHandler: { (url, error) in
				// upon completion execute javasript function for Lightbox to proceed
	      self.webView.evaluateJavaScript("window.Trustly.proceedToChooseAccount();", completionHandler: nil)
    })
    webSession.prefersEphemeralWebBrowserSession = true
    webSession.presentationContextProvider = self
    webSession.start()
}

Summary & Next Steps

That’s it! You have successfully handled OAuth scenarios for your Trustly integration. To see the code examples included in this guide in the context of a complete demo, see the Trustly OAuth Webview Demo repository.

If you have any trouble with your OAuth integration please reach out to us via [email protected] for assistance.

FAQ

If more banks require OAuth in the future, will I need to refactor my app to handle them?

Not likely. Because Trustly generates the url to be opened after the user selects a bank, the logic to handle different banks and their URLs is continuously updated and maintained by Trustly. Your mobile app only needs to handle opening the external url triggered by the Lightbox.

However, it is not possible to guarantee no future updates will be needed to handle other concerns. To minimize future maintenance and for the best developer experience, Trustly recommends using our native mobile SDKs.

My entire checkout experience is served as a standalone web app that is loaded as a webview into my mobile app. If the Trustly Lightbox is loaded within the checkout experience will I need to follow this guide for a successful mobile integration?

Yes. Though the Trustly Lightbox may work by default in a traditional web browser on desktop or mobile, any mobile application that has a Trustly integration but is not using a mobile-native Trustly SDK will need to consider the Webview OAuth guide to ensure proper functionality.

My checkout experience is served over multiple channels (mobile apps, web, etc.) and uses the same web app to launch the lightbox across all platforms. Do I need to treat the urlscheme and integrationContext differently when the user is on a web browser and not a webview in mobile app?

Yes. When passing the integrationContext and urlScheme parameters, the Trustly Lightbox assumes the user is coming from a mobile app and adjusts its behavior to support the approach outlined in this guide. If your app passes these variables from a web browser, your users may not be able to login to OAuth banks. You can handle this several ways, but one approach is add a query parameter when opening the web page from a mobile app e.g. webapp.com?integrationContext=inAppBrowser and dynamically add the integrationContext and urlScheme to the establish data within your web app based on the presence of this parameter.

When a user selects an OAuth bank, how does the Lightbox know if there is a bank app present or not on the user’s device? Doesn’t Chase have multiple OAuth login URLs?

The Trustly Lightbox has no knowledge of the apps available on a user’s device. However, Trustly does know whether a bank app (such as Chase) has a supported Universal Link that is capable of opening a mobile app. In the case of Chase, though they do have multiple login URLs, Trustly will call the one that is a registered Universal Link. If the user does not have the Chase app installed, the Universal Link will open in the active browser window.

Given these changes to the behavior of the Lightbox, are there any notable changes to the event notifications that the Lightbox provides?

No. Although there are some important changes in the behavior of the Lightbox on a mobile device, the event notifications are unchanged and the mechanism to subscribe to these events remains the same as well.

What happens if a user closes my app (or my app crashes) before the user has successfully authenticated using their bank’s app?

After a user successfully authenticates in their bank’s app, the bank app will open a call back URL in the device’s default browser. This page will be a Trustly web page that captures the status of the authorization process before returning to your app via the urlScheme field provided by your app upon activating the lightbox. As long as your app handles that provided urlScheme appropriately, the user should be returned to the Trustly Lightbox within your app.