Addressing Security-Related Errors for iPhone Users
  • 28 Jan 2025
  • 4 Minutes to read
  • Dark
    Light

Addressing Security-Related Errors for iPhone Users

  • Dark
    Light

Article summary

This document outlines a solution to resolve security-related errors encountered when using TouchNet as a Payment Gateway within an iframe on Apple devices. This approach leverages client-side JavaScript to adapt the behavior based on the device type, ensuring a seamless user experience.

Background

The Problem

Apple device users experience a security-related error and cannot continue registering for an Event when the Event is in an iframe, and the Payment Gateway is TouchNet. The security restrictions (e.g., cross-site scripting rules) prevent cross-domain redirects within iframes, which results in the following.

  • Session cookies and security headers are blocked.
  • An error interrupts the user’s ability to complete transactions.

In short, TouchNet’s architecture includes a redirect that occurs within an iframe, which is considered a security issue and blocked by Apple.

Sample Use Case:

An organization’s mobile app uses iframes to display Events. Because of Apple’s restrictions, TouchNet's redirect flow fails, requiring an alternative solution.

Recommended Solution

We suggest customers use client-side JavaScript to:

  • Detect if the potential Attendee is on an iPhone.
  • Open the Event in a new window for iPhone users.
  • Continue loading the Event in an iframe for other devices.

Technical Solution

Why TouchNet and Iframes Don’t Work on Apple Devices

TouchNet’s cross-domain redirect flow is incompatible with iframes on Apple devices because:

  • Session cookies and security headers cannot be securely shared across domains in an iframe.
  • Apple's browser policies block such redirects for security reasons.

Key Elements of the Solution

  • Device Detection: Check the navigator.userAgent to identify iPhone users.
  • Dynamic Behavior:
    • For iPhone users, open the Event in a new window using window.open.
    • For other devices, load the TouchNet script dynamically into an iframe.
  • Responsiveness: The script ensures a consistent and user-friendly interface on all devices.

How It Works

  1. Device Detection: The isIPhone function checks the navigator.userAgent to identify iPhone users.
  2. Dynamic Behavior:
    • For iPhone Users:
      • Users see a message and the Open Event button.
      • After clicking the Open Event button, the Event opens in a new window using window.open.
    • For Other Devices:
      • The TouchNet script is dynamically added to the page, and the page loads in an iframe.

Implementation Steps

Critical Step

The script must be added to the hosting page and cannot be managed within the Blackthorn Events application.

  1. Update HTML: Replace your existing iframe setup with the provided HTML structure and script.
  2. Customize Parameters: Replace scriptPath with the data path specific to your Event.
  3. Deploy and Test:
    1. Upload the updated HTML to your server.
    2. Test the implementation on both iPhone and non-iPhone devices.

Sample Code

Copy and paste this code in the body tag.

<div id="ios-message" style="display: none;">
    <p id="iphone-message">
        To register for this event, please click the button below to open the event in a new window.
    </p>
    <button id="open-event-button">Open Event</button>
</div>

<div id="event-container"></div>

<script>
    // Function to detect if the device is an iPhone
    function isIPhone() {
        return /iPhone/i.test(navigator.userAgent);
    }

    // Function to initialize the event loader
    function initializeEventLoader(eventUrl, scriptPath) {
        if (isIPhone()) {
            handleIPhoneCase(eventUrl, scriptPath);
        } else {
            loadEventScript(eventUrl, scriptPath);
        }
    }

    // Function to handle the iPhone-specific case
    function handleIPhoneCase(eventUrl, scriptPath) {
        const message = document.getElementById("ios-message");
        const button = document.getElementById("open-event-button");
        const finalUrl = `${eventUrl}${scriptPath}`;

        // Show the message and button
        message.style.display = "block";

        // Attach the click event to the button
        button.addEventListener("click", () => {
            window.open(finalUrl, "_blank", "noopener,noreferrer");
        });
    }

    // Function to load the event script for non-iPhone devices
    function loadEventScript(eventUrl, scriptPath) {
        const script = document.createElement("script");
        script.src = `${eventUrl}/loader`;
        script.setAttribute("data-path", scriptPath);

        // Append the script to the container
        const eventContainer = document.getElementById("event-container");
        eventContainer.appendChild(script);
    }

    // Initialize on page load
    document.addEventListener("DOMContentLoaded", () => {
        const eventUrl = "https://events.blackthorn.io";
        const eventPath = "/5e53zvb7/5a195eDuv9X"; // <<< Change this to your event path
        initializeEventLoader(eventUrl, eventPath);
    });
</script>

Here is the complete HTML code with the solution embedded and some CSS changes.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #cdcdcd;
        }

        #ios-message {
            background-color: #ffffff;
            border: 1px solid #cdcdcd;
            padding: 1rem;
            border-radius: 5px;
            margin-bottom: 20px;
            text-align: center;
            padding-top: 0;
        }

        #iphone-message {
            font-size: 16px;
            line-height: 1.5;
            color: #333;
            text-align: center;
            margin-bottom: 1rem;
        }

        #open-event-button {
            padding: 10px 20px;
            font-size: 16px;
            background-color: #007bff;
            color: #fff;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            margin: 0 auto;
        }

        #open-event-button:hover {
            background-color: #0056b3;
        }

        #event-container {
            height: 900px;
            margin-top: 20px;
        }
    </style>
</head>

<body>

    <h1>Iframe Demo</h1>

    <div id="ios-message" style="display: none;">
        <p id="iphone-message">
            To register for this event, please click the button below to open the event in a new window.
        </p>
        <button id="open-event-button">Open Event</button>
    </div>

    <div id="event-container"></div>

    <script>
        // Function to detect if the device is an iPhone
        function isIPhone() {
            return /iPhone/i.test(navigator.userAgent);
        }

        // Function to initialize the event loader
        function initializeEventLoader(eventUrl, scriptPath) {
            if (isIPhone()) {
                handleIPhoneCase(eventUrl, scriptPath);
            } else {
                loadEventScript(eventUrl, scriptPath);
            }
        }

        // Function to handle the iPhone-specific case
        function handleIPhoneCase(eventUrl, scriptPath) {
            const message = document.getElementById("ios-message");
            const button = document.getElementById("open-event-button");
            const finalUrl = `${eventUrl}${scriptPath}`;

            // Show the message and button
            message.style.display = "block";

            // Attach the click event to the button
            button.addEventListener("click", () => {
                window.open(finalUrl, "_blank", "noopener,noreferrer");
            });
        }

        // Function to load the event script for non-iPhone devices
        function loadEventScript(eventUrl, scriptPath) {
            const script = document.createElement("script");
            script.src = `${eventUrl}/loader`;
            script.setAttribute("data-path", scriptPath);

            // Append the script to the container
            const eventContainer = document.getElementById("event-container");
            eventContainer.appendChild(script);
        }

        // Initialize on page load
        document.addEventListener("DOMContentLoaded", () => {
            const eventUrl = "https://events.blackthorn.io";
            const eventPath = "/5e53zvb7/5a195eDuv9X"; // <<< Change this to your event path
            initializeEventLoader(eventUrl, eventPath);
        });
    </script>
</body>

Testing and Validation

Pre-requisite: Ensure pop-ups are not blocked for iPhone users.

Test Scenarios

  • iPhone Devices:
    • Open the page and verify that the message and Open Event button are displayed.
    • Click Open Event and confirm the Event opens in a new browser window.
  • Non-iPhone Devices:
    • Open the page and verify that the Event loads directly in an iframe.

End-User Experience

  • iPhone Users: The Event opens seamlessly in a new browser window, bypassing Apple’s security restrictions.
  • Other Users: The Event continues to load within the iframe as before.