NAV
OAuth Guides
cURL Android Swift
  • Overview
  • OAuth in Atrium
  • Using OAuth in Connect with WebViews
  • Testing with MXBank
  • Overview

    OAuth provides a more secure connection for clients and their customers. As a token-based solution, credentials are handled entirely by the OAuth provider and exchanged for a token that MX can use.

    In order to connect accounts via OAuth, the user will need to be directed to the OAuth provider's site for authentication and authorization. Once the user has successfully authenticated, they will be redirected back to MX and then to the client app. This may introduce changes to how your integration works.

    API implementations

    Clients using the API to connect users will need to create the OAuth member, generate an OAuth URL for that member, send the user to that URL, and get the user back to their app.

    Connect widget implementations

    Clients utilizing the Connect widget in a desktop or mobile browser should not have to make any additional implementation changes.

    WebView implementations, however, will need to send the user to the OAuth URL and configure a scheme to get the user back to their app.

    OAuth in Atrium

    Members

    A member represents the relationship between a user and an institution, and creating one is how you connect one to the other. Thus, multiple members may be attached to a single user, e.g., one for their bank, another for their mortgage provider, another for their credit card provider, etc.

    Member fields

    Field Data type Description
    aggregated_at String The date and time the account was last aggregated.
    connection_status String The status of a member's aggregation. Read more about these statuses below.
    guid String A unique identifier for the member. Defined by MX.
    identifier String A unique, enforced identifier for the member. Defined by you.
    institution_code String Unique identifier for the institution. Defined by MX.
    is_being_aggregated Boolean This value is true if the member is being aggregated at the time of the request and false otherwise.
    metadata String Additional information you can store on this member.
    name String The name of the member. If omitted as a parameter when creating the member, the institution name within the MX platform will be used, e.g., "Chase Bank."
    status String The status of a member's aggregation. This field will soon be deprecated. Use connection_status above as more detailed indicator of a member's status.
    successfully_aggregated_at String The date and time the member was successfully aggregated.
    user_guid String A unique identifier for the user. Defined by MX.

    Connection status definitions

    Connection status id (integer) Connection status (string) Definition Next steps End-user message
    null null The member exists but does not have credentials. None. None.
    0 CREATED The member is new and has not yet been aggregated. Aggregate the member once the end user logs in; poll for a status update. Connecting to {...} ...
    1 PREVENTED MX is preventing aggregation until the member’s credentials have been updated. Display end-user message; after end user has updated their credentials, aggregate again. The last 3 attempts to connect have failed. Please re-enter your credentials to continue importing data.
    2 DENIED The credentials provided for the member were invalid. Display end-user message; after end user has updated their credentials, aggregate again. The credentials entered do not match your credentials at this institution. Please re-enter your credentials to continue importing data.
    3 CHALLENGED The member has been challenged by multi-factor authentication. Display end-user message; follow MFA pathway; after the user answers MFA, poll for a status update. To authenticate your connection to {...}, please answer the following challenge(s).
    4 REJECTED An MFA challenge was answered incorrectly. Display end-user message; another challenge may follow or aggregation may need to be restarted. The answer or answers provided were incorrect. Please try again.
    5 LOCKED The financial institution is preventing authentication. The end user must contact the financial institution. Display end-user message. Your account is locked. Please log in to the appropriate website for {...} and follow the steps to resolve the issue.
    6 CONNECTED The member was successfully authenticated and data is now aggregating. Display the account as having been connected. Connected to [...] ...
    7 IMPEDED The end user’s attention is required at their online banking institution, e.g., there is a marketing message that must be viewed, terms and conditions that must be accepted, etc. Display end-user message. Your attention is needed at this institution's website. Please log in to the appropriate website for {...} and follow the steps to resolve the issue.
    8 RECONNECTED The member has been migrated to a new data source and aggregation is likely to trigger one-time password MFA. MX will not perform background aggregation in order to avoid unnecessarily disruptive texts, emails, etc. The member must be re-aggregated in the foreground with the end user present. Aggregate the member once the end user logs in; poll for a status update. Reconnecting to {...} ...
    9 DEGRADED Aggregation has failed at least three times within a short period of time. Display end-user message. We are upgrading this connection. Please try again later.
    10 DISCONNECTED Aggregation has failed at least three times and has not succeeded for at least two weeks. Display end-user message. It looks like your data from {...} cannot be imported. We are working to resolve the issue.
    11 DISCONTINUED The connection to this financial institution is no longer available. Display end-user message. Connections to this institution are no longer supported. You may create a manual account and use manual transactions to track data for this account.
    12 CLOSED The end user, MX, the client, or a partner has marked the member as closed. Display end-user message. This connection has been closed. You may track this account manually. If reopened, you may connect the institution again.
    13 DELAYED Aggregating the member has taken longer than expected and it has not yet been connected. Display end-user message; poll for a status update. Importing your data from {...} may take a while. Please check back later.
    14 FAILED Aggregation failed without being connected. Display end-user message; try aggregating again later. There was a problem validating your credentials with {...}. Please try again later.
    15 UPDATED The member has been updated — i.e., credentials have been updated — but it has not yet been connected. Aggregate the member once the end user logs in; poll for a status update. Connecting to {...} ...
    16 DISABLED Aggregation has been momentarily paused, but the member is still connected. Display end-user message. Importing data from this institution has been disabled. Please contact us if you believe it has been disabled in error.
    17 IMPORTED MX does not have credentials and will not try to aggregate the member until the end user provides credentials. Display end-user message; re-aggregate after the end user updates credentials. You must re-authenticate before your data can be imported. Please enter your credentials for {...}.
    18 RESUMED The answer to an MFA challenge was received, but it is not yet clear whether it was correct. Poll for a status update. Connecting to {...} ...
    19 EXPIRED The MFA answer was not provided within the time allotted by the financial institution. Display end-user message; re-aggregate the member if the end user initiates it. The answer or answers were not provided in time. Please try again.
    20 IMPAIRED The member is missing some or all credentials needed in order to connect. Display end-user message; re-aggregate after the end user updates credentials. You must re-authenticate before your data can be imported. Please enter your credentials for {...}.
    21 PENDING The member is using OAuth to authenticate credentials and still needs to go through the financial institution's OAuth process. Redirect the end user to the oauth_window_uri provided in the create member response, or request one through the generate OAuth window URI endpoint. None.

    Create member

    POST /users/{user_guid}/members
    

    Example request

    $ curl -i -X POST 'https://vestibule.mx.com/users/{user_guid}/members' \
      -H 'Accept: application/vnd.mx.atrium.v1+json' \
      -H 'Content-Type: application/json' \
      -H 'MX-API-Key: {mx_api_key}' \
      -H 'MX-Client-ID: {mx_client_id}' \
      -d '{
            "member":{
              "institution_code":"chase",
              "metadata": "Additional information",
              "is_oauth": true
            }
          }'
    

    Example response

    Status: 202 Accepted
    
    {
      "member": {
        "aggregated_at": "2016-10-13T17:57:36+00:00",
        "connection_status": "PENDING",
        "guid": "MBR-7c6f361b-e582-15b6-60c0-358f12466b4b",
        "identifier": "unique_id",
        "institution_code": "chase",
        "is_being_aggregated": true,
        "metadata": "Additional information",
        "name": "Chase Bank",
        "oauth_window_uri": "https://dev-firefly1.moneydesktop.com/oauth/predirect_to/MBR-7aa13bdb-2866-ba38-b326-d9fb32268f9b/lk76038j23cAstpxnt4g58vybqZqg9vnn0lz29bwmvc40tss5rhjxlyf53pns05vfd99y5m766fdj7njpf615A5j3013xmdqA9mwz5nAgs9gr2887h0krh1l4gbAxfp8ztnpd47wk6j2ztjbz1f0lyr73nbxft0pwjwkqdjnfpA8ktn9tbvAbxqn40645vs4kxxcAx2rjc0vyxhtfhsk5vpq3Anrmdjtfj8qlpc617bkntbAwlpylfqf4AshyvA6lpmn5ptrzqhd933k98rzymzmjgqy9m25np0fqm7zw6Akr8qyy5ckb6wxxA31vfjw5xm7td8z6vh7d0djwsgw34Awvj58psh2l7xk9414",
        "status": null,
        "successfully_aggregated_at": null,
        "user_guid": "USR-fa7537f3-48aa-a683-a02a-b18940482f54"
      }
    }
    
    POST /users/{user_guid}/members
    

    Example request with optional OAuth parameters

    $ curl -i -X POST 'https://vestibule.mx.com/users/{user_guid}/members' \
      -H 'Accept: application/vnd.mx.atrium.v1+json' \
      -H 'Content-Type: application/json' \
      -H 'MX-API-Key: {mx_api_key}' \
      -H 'MX-Client-ID: {mx_client_id}' \
      -d '{
            "member":{
              "institution_code":"chase",
              "metadata": "Additional information",
              "is_oauth": true
            },
            "referral_source": "APP",
            "ui_message_webview_url_scheme": "yourapp"
          }'
    

    Example response

    Status: 202 Accepted
    
    {
      "member": {
        "aggregated_at": "2016-10-13T17:57:36+00:00",
        "connection_status": "PENDING",
        "guid": "MBR-7c6f361b-e582-15b6-60c0-358f12466b4b",
        "identifier": "unique_id",
        "institution_code": "chase",
        "is_being_aggregated": true,
        "metadata": "Additional information",
        "name": "Chase Bank",
        "oauth_window_uri": "https://dev-firefly1.moneydesktop.com/oauth/predirect_to/MBR-7aa13bdb-2866-ba38-b326-d9fb32268f9b/lk76038j23cAstpxnt4g58vybqZqg9vnn0lz29bwmvc40tss5rhjxlyf53pns05vfd99y5m766fdj7njpf615A5j3013xmdqA9mwz5nAgs9gr2887h0krh1l4gbAxfp8ztnpd47wk6j2ztjbz1f0lyr73nbxft0pwjwkqdjnfpA8ktn9tbvAbxqn40645vs4kxxcAx2rjc0vyxhtfhsk5vpq3Anrmdjtfj8qlpc617bkntbAwlpylfqf4AshyvA6lpmn5ptrzqhd933k98rzymzmjgqy9m25np0fqm7zw6Akr8qyy5ckb6wxxA31vfjw5xm7td8z6vh7d0djwsgw34Awvj58psh2l7xk9414?referral_source=APP&ui_message_webview_url_scheme=yourapp",
        "status": null,
        "successfully_aggregated_at": null,
        "user_guid": "USR-fa7537f3-48aa-a683-a02a-b18940482f54"
      }
    }
    

    This endpoint allows you to create a new member.

    Calling the create member endpoint with is_oauth set to true allows you to create a member without having to include the institution's required credentials in your request. The member will be created with a connection status of PENDING and a redirect URI will be provided in the oauth_window_uri field. Making a request to this URI will then take the user to the registered OAuth application where they can provide credentials and choose what data to share with MX. After completing the OAuth process, the connection status will be updated.

    Parameter Data type Description Required?
    identifier String A unique enforced identifier for the member, defined by you. No
    institution_code String Unique code for the institution to which the member will connect. Yes
    metadata String Additional information you can store on this member. No
    skip_aggregation Boolean Setting this parameter to true will prevent the member from automatically aggregating when it is created. No
    is_oauth boolean The member does not require credentials when being created; instead, the member is created with a PENDING status and the response to the request will contain the oauth_window_uri attribute; the end user authenticates credentials with OAuth. No
    referral_source string Should be either BROWSER or APP depending on the implementation. Default is BROWSER. This field should not be nested under the member when given in a request body; it can also be sent as a query parameter to the the generate OAuth window URI endpoint. No
    ui_message_webview_url_scheme string A scheme for routing the user back to the application state they were previously in. This field should not be nested under the member when given in a request body; it can also be sent as a query parameter to the the generate OAuth window URI endpoint. No

    Generate OAuth window URI

    GET /users/{user_guid}/members/{member_guid}/oauth_window_uri
    

    Example request

    $ curl -i -X GET 'https://vestibule.mx.com/users/{user_guid}/members/{member_guid}/oauth_window_uri' \
      -H 'Accept: application/vnd.mx.atrium.v1+json' \
      -H 'MX-API-Key: {mx_api_key}' \
      -H 'MX-Client-ID: {mx_client_id}'
    

    Example response

    Status: 200 OK
    
    {
      "member": {
        "aggregated_at": "2016-10-13T18:07:57+00:00",
        "connection_status": "CONNECTED",
        "guid": "MBR-7c6f361b-e582-15b6-60c0-358f12466b4b",
        "identifier": "unique_id",
        "institution_code": "chase",
        "is_being_aggregated": false,
        "metadata": "{\"credentials_last_refreshed_at\": \"2015-10-15\"}",
        "name": "Chase Bank",
        "oauth_window_uri": "https://dev-firefly1.moneydesktop.com/oauth/predirect_to/MBR-b5f96507-4c9f-492d-8bb0-810bbe2b8c13/zz9A0dsm36n744jtAApwl7pgpyZApchszmv05jzA2x3bv3j73bfp00g1nszk3nh77zn9jg1vgqt95hsp2r5r1v5lspt7w9fsyqpfy7h902vb41b9b83l01jhbn23lAzvjqggs52pmgx40f41vjxkylp68jh8zl2l33mlzww83xq9dmm9fs0l7t6hfAdls1xmn26ph2xtdxtx3kg8thbkpnxwnd67mlxnqsjqfAjAfjgAzz5zdbsfqqz2hf4dl5v5h2Ax7kx1gz7wmnk7sfk5xtvvptj4r1vqn1wl92dzg0tAzxyvg75d6A3gwpA98pb4s3d1c0nw3zq0mfjdkgsxp7ppgl9x7qvv97n81d53",
        "status": "COMPLETED",
        "successfully_aggregated_at": "2016-10-13T17:57:38+00:00",
        "user_guid": "USR-fa7537f3-48aa-a683-a02a-b18940482f54"    
      }
    }
    

    This endpoint will generate an oauth_window_uri for the specified member.

    Generating a new oauth_window_uri is necessary in order to send the end user through the OAuth process again. There are several situations where you might want to do this. Below are a few examples: * A previous attempt at OAuth failed — for instance if the end user closed the OAuth window before completing the process. * The financial institution has revoked a previous OAuth token or the token has expired.

    The member in question must be connected to an institution which supports OAuth. if the institution does not support OAuth, a 400 Bad Request error will be returned with the message Member cannot use OAuth.

    Step-by-step guide for creating an OAuth member

    1. Search for an institution

    GET /institutions/{institution_code}
    

    Example request

    $ curl -i -X GET 'https://vestibule.mx.com/institutions/mxbank' \
      -H 'Accept: application/vnd.mx.atrium.v1+json' \
      -H 'MX-API-Key: {mx_api_key}' \
      -H 'MX-Client-ID: {mx_client_id}'
    

    Example response

    Status: 200 OK 
    
    {
      "institution": {
        "code": "mxbank",
        "medium_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/100x100/default_100x100.png",
        "name": "MX Bank",
        "small_logo_url": "https://content.moneydesktop.com/storage/MD_Assets/Ipad%20Logos/50x50/default_50x50.png",
        "supports_account_identification": true,
        "supports_account_verification": true,
        "supports_oauth": true,
        "url": "https://www.mx.com"
      }
    }
    

    Verify that supports_oauth: true is in the response.

    2. List users

    GET /users
    

    Example request

    
    # Here, we're checking to see what users are available for testing.
    # Note that this endpoint returns paginated results and accepts optional pagination parameters.
    
    $ curl -i -X GET 'https://vestibule.mx.com/users' \
      -H 'Accept: application/vnd.mx.atrium.v1+json' \
      -H 'MX-API-Key: {mx_api_key}' \
      -H 'MX-Client-ID: {mx_client_id}'
    

    Example response

    Status: 200 OK
    
    {
      "users": [
        {
          "guid": "USR-fa7537f3-48aa-a683-a02a-b18940482f54",
          "identifier": "unique_id",
          "is_disabled": false,
          "metadata": "{\"first_name\": \"Steven\"}"
        },
        {
          "guid": "USR-7c6f361b-e582-15b6-60c0-358f12466b4b",
          "identifier": "unique_id",
          "is_disabled": false,
          "metadata": "{\"first_name\": \"Barb\"}"
        }
      ]
    }
    

    3. Create a member

    POST /users/{user_guid}/members
    

    Example request

    $ curl -i -X POST 'https://vestibule.mx.com/users/{user_guid}/members' \
      -H 'Accept: application/vnd.mx.atrium.v1+json' \
      -H 'Content-Type: application/json' \
      -H 'MX-API-Key: {mx_api_key}' \
      -H 'MX-Client-ID: {mx_client_id}' \
      -d '{
            "member": {
              "institution_code": "chase",
              "is_oauth: true,
              "skip_aggregation": false
            }
          }'
    

    Example response

    Status: 202 Accepted
    
    {
      "member": {
        "aggregated_at": null,
        "connection_status": "PENDING",
        "guid": "MBR-7c6f361b-e582-15b6-60c0-358f12466b4b",
        "identifier": null,
        "institution_code": "chase",
        "is_being_aggregated": false,
        "metadata": null,
        "name": "Chase Bank",
        "oauth_window_uri": "https://dev-firefly1.moneydesktop.com/oauth/predirect_to/MBR-b5f96507-4c9f-492d-8bb0-810bbe2b8c13/zz9A0dsm36n744jtAApwl7pgpyZApchszmv05jzA2x3bv3j73bfp00g1nszk3nh77zn9jg1vgqt95hsp2r5r1v5lspt7w9fsyqpfy7h902vb41b9b83l01jhbn23lAzvjqggs52pmgx40f41vjxkylp68jh8zl2l33mlzww83xq9dmm9fs0l7t6hfAdls1xmn26ph2xtdxtx3kg8thbkpnxwnd67mlxnqsjqfAjAfjgAzz5zdbsfqqz2hf4dl5v5h2Ax7kx1gz7wmnk7sfk5xtvvptj4r1vqn1wl92dzg0tAzxyvg75d6A3gwpA98pb4s3d1c0nw3zq0mfjdkgsxp7ppgl9x7qvv97n81d53"
        "successfully_aggregated_at": null,
        "user_guid": "USR-fa7537f3-48aa-a683-a02a-b18940482f54"
      }
    }
    

    4. Redirect user to the registered OAuth Application

    Open a browser window to the oauth_window_uri. The user will be taken to the institution's registered OAuth application page. Here, the user can enter their credentials and choose what to share with MX.

    Communicating with the OAuth window

    // Open a new window to the oauth uri. Keep a handle to the opened window.
    const oauthWindow = window.open(oauth_window_uri)
    
    window.addEventListener('message', function(data) {
      if (data.type === 'oauthComplete/success') {
        /**
         * At this point you will want to keep polling the member until the job is
         * complete. But you can close the oauth window now.
         */
        if (oauthWindow) oauthWindow.close()
      } else if (data.type === 'oauthComplete/error') {
        /**
         * At this point the user either rejected the OAuth terms or something went
         * wrong with the redirect back to MX.
         */
        if (oauthWindow) oauthWindow.close()
      }
    })
    

    When the user completes the process, the opened window will attempt to send a post message back to you via window.opener.postMessage. You can use this post message as a way to make flow decisions in your own app.

    If the process was successful the post message will have the following payload:

    { mx: true, type: "oauthComplete/success" }

    At this point the Member will be authenticated and a Job will be started. You will want to continue polling the member until the job is finished.

    If the user completed the process, but either rejected the terms or had an error in the process, the post message will be:

    { mx: true, type: "oauthComplete/error" }

    5. Poll the member status

    GET /users/{user_guid}/members/{member_guid}/status
    

    Example request

    $ curl -i -X GET 'https://vestibule.mx.com/users/{user_guid}/members/{member_guid}/status' \
      -H 'Accept: application/vnd.mx.atrium.v1+json' \
      -H 'MX-API-Key: {mx_api_key}' \
      -H 'MX-Client-ID: {mx_client_id}'
    

    Example response

    Status: 200 OK
    
    {
      "member": {
        "aggregated_at": "2016-10-13T18:07:57+00:00",
        "connection_status": "PENDING",
        "guid": "MBR-7c6f361b-e582-15b6-60c0-358f12466b4b",
        "has_processed_accounts": true,
        "has_processed_transactions": false,
        "identifier": "unique_id",
        "institution_code": "chase",
        "is_being_aggregated": false,
        "metadata": "{\"credentials_last_refreshed_at\": \"2015-10-15\"}",
        "name": "Chase Bank",
        "status": "COMPLETED",
        "successfully_aggregated_at": "2016-10-13T17:57:38+00:00",
        "user_guid": "USR-fa7537f3-48aa-a683-a02a-b18940482f54"
      }
    }
    

    Example CHALLENGED status response

    {
      "member": {
        "aggregated_at":"2016-10-13T18:24:37+00:00",
        "challenges": [
          {
            "field_name": null,
            "guid": "CRD-1ec152cd-e628-e81a-e852-d1e7104624da",
            "label": "What city were you born in?",
            "type": "TEXT"
          }
        ],
        "connection_status": "CHALLENGED",
        "guid": "MBR-7c6f361b-e582-15b6-60c0-358f12466b4b",
        "has_processed_accounts": false,
        "has_processed_transactions": false,
        "is_being_aggregated": true,
        "status": "CHALLENGED",
        "successfully_aggregated_at": "2016-10-13T18:08:04+00:00"
      }
    }
    

    Using OAuth in Connect with WebViews

    Example request

    curl -i -X POST 'https://vestibule.mx.com/users/{user_guid}/connect_widget_url' \
      -H 'Accept: application/vnd.mx.atrium.v1+json' \
      -H 'Content-Type: application/json' \
      -H 'MX-API-Key: {mx_api_key}' \
      -H 'MX-Client-ID: {mx_client_id}'
      -d '{ "is_mobile_webview": true, "ui_message_version": 4, "ui_message_webview_url_scheme": "{app scheme}" }'
    

    There are three configuration options WebViews will need in order to have the optimal OAuth flow:

    In-depth configuration documentation can be found here.

    In-depth documentation on postMessages can be found here.

    Redirecting the user

    Example redirect:

    Select Java or Swift for WebView client examples.
    
    /**
     * This Client will capture urls from MX and cancel them. It will specifically
     * handle the oauthRequested URL. You will want to set this client as your
     * WebView's client or add this functionality to your own.
     */
    public class MXWebViewClient extends WebViewClient {
        private Activity activity;
    
        public MXWebViewClient(Activity mainActivity) {
            activity = mainActivity;
        }
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            // Ensure you are looking for schemes from both 'mx', 'atrium' and whatever you configured
            // ui_message_webview_url_scheme to be. In this example, it was 'appscheme'.
            boolean isFromMX = url.startsWith("mx://")  || url.startsWith("atrium://") || url.startsWith("appscheme://");
    
            if (isFromMX) {
                try {
                    Uri mxURI = Uri.parse(url);
    
                    // Handle the oauth url redirect. Send the user to the URL given.
                    if (mxURI.getPath().equals("/oauthRequested")) {
                        JSONObject mxMetaData = new JSONObject(mxURI.getQueryParameter("metadata"));
                        String oauthURL = mxMetaData.getString("url");
                        Uri oauthPage = Uri.parse(oauthURL);
                        Intent intent = new Intent(Intent.ACTION_VIEW, oauthPage);
                        activity.startActivity(intent);
                    }
                } catch (Exception err) {
                    Log.e("sb: Error creating URI", err.getMessage());
                }
                return true;
            }
    
            return false;
        }
    }
    
    /**
     * Set up the WebView to capture URLs. You will want to cancel all urls from MX.
     */
    class ViewController: UIViewController, WKNavigationDelegate {
    
        var webView: WKWebView!
        let appScheme = "appscheme://"
        let mxScheme = "mx://"
        let atriumScheme = "atrium://"
    
        func webView(_ webView: WKWebView,
                     decidePolicyFor navigationAction: WKNavigationAction,
                     decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
    
            // Ensure you are looking for schemes from both 'mx', 'atrium', and whatever you configured
            // ui_message_webview_url_scheme to be. In this example, it was 'appscheme'.
            let url = navigationAction.request.url?.absoluteString
            let isFromMX = url?.hasPrefix(appScheme) == true || url?.hasPrefix(mxScheme) == true || url?.hasPrefix(atriumScheme) == true
    
            if isFromMX {
                let urlc = URLComponents(string: surl ?? "")
                let path = urlc?.path ?? ""
                // there is only one query parameter ("metadata")
                // so just grab the first one
                let metaDataQueryItem = urlc?.queryItems?.first
    
                if path == "/oauthRequested" {
                    handleOauthRedirect(payload: metaDataQueryItem)
                }
    
                // Cancel request
                decisionHandler(.cancel)
                return
            }
    
            // Allow request
            decisionHandler(.allow)
        }
    
        /*
         * Handle the oauthRequested event. Parse out the OAuth URL from the event
         * and open Safari to that URL
         * NOTE: This code is somewhat optimistic, you'll want to add error handling
         * that makes sense for your app.
         */
        func handleOauthRedirect(payload: URLQueryItem?) {
            let metadataString = payload?.value ?? ""
    
            do {
                if let json = try JSONSerialization.jsonObject(with: Data(metadataString.utf8), options: []) as? [String: Any] {
                    if let url = json["url"] as? String {
                        // open safari with the url from the json payload
                        UIApplication.shared.open(URL(string: url)!)
                    }
                }
            } catch let error as NSError {
                print("Failed to parse payload: \(error.localizedDescription)")
            }
        }
    }
    

    Since the MX WebView can't reliably send the user from the app to the OAuth provider's site in a native browser, the containing iOS or Android app will need to. To facilitate this, your app will need to react to the connect/oauthRequested postMessage request:

    <ui_message_webview_url_scheme>://connect/oauthRequested?metadata=...

    The OAuth URL is inside of the metadata query parameter under the url key.

    Getting back to your app

    Once the user completes the OAuth process, MX will send the user back to the client app via a URL scheme like so:

    <ui_message_webview_url_scheme>://oauth_complete?status=<success|error>&member_guid=<guid>

    This part is optional for OAuth, but highly recommended. If this is not set, the user will end on an MX page with a success or error message and will have to navigate back to your app manually. Make sure to pick a scheme that your app can respond to.

    Testing with MXBank

    You will only be able to test OAuth flows in the integration environment with the MX Bank (OAuth).

    See the testing docs for more detail