> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go.gbgplc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> Trust boundaries, transport security, and production hardening.

This guide covers the security model of GBGBridge, including transport safety, content policies, and best practices for production deployments.

## Security Model Overview

GBGBridge operates within the iOS WebKit security model. The bridge is a thin messaging layer — it does not bypass any platform security mechanisms. All communication between the web journey and the native host goes through WebKit's `WKScriptMessageHandler` (incoming) and `evaluateJavaScript` (outgoing).

### Trust Boundaries

```mermaid theme={null}
flowchart TB
    subgraph sandbox["iOS App Sandbox"]
        native["Native Host Code\n(fully trusted)"]
        bridge["Bridge"]
        webview["WKWebView\n(sandboxed web)"]
        native <--> bridge
        bridge <--> webview
    end
```

* **Native host code** runs with full app permissions. Handlers can access any iOS API.
* **Web content in WKWebView** runs in a sandboxed web process. It cannot access native APIs except through the bridge message handler.
* **The bridge** is the controlled interface between these two zones.

## Transport Security

Bridge messages never traverse the network — they ride on WebKit's IPC channels — but the journey URL itself does, so transport security has two distinct concerns: how messages move between native and web (covered first) and how the journey is loaded over HTTPS (covered second).

### Message Channel

Messages travel over WebKit's internal IPC mechanism:

* **Web → Native**: `window.webkit.messageHandlers.gbgBridge.postMessage()` — uses WebKit's built-in script message handler. This is a same-process or inter-process call managed by WebKit, not a network request.
* **Native → Web**: `webView.evaluateJavaScript()` — executes JavaScript in the WebView's context.

Neither channel traverses the network. Messages are memory-to-memory within the device.

### Network Security (Journey Loading)

The web journey itself is loaded over the network. To ensure network security:

* Always use HTTPS in production. iOS App Transport Security (ATS) enforces this by default.
* Do not disable ATS globally. If you need local development access, use the scoped exception:

```xml theme={null}
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsLocalNetworking</key>
    <true/>
</dict>
```

* Pin certificates if your security requirements demand it. Implement `WKNavigationDelegate.webView(_:didReceive:completionHandler:)` for custom certificate validation.

## Content Security

### Bootstrap Script Injection

The bridge bootstrap script is injected at **document start** via `WKUserScript`. This runs before any web content loads, ensuring the `window.GBGBridge` namespace exists when the journey code initializes.

The default bootstrap script is minimal:

```javascript theme={null}
window.GBGBridge = window.GBGBridge || {};
window.GBGBridge.receive = window.GBGBridge.receive || function(){};
```

### Custom Bootstrap Scripts

If you provide a custom `bootstrapScript` in `BridgeConfiguration`, ensure it does not:

* Expose sensitive native data to the web context.
* Define functions that bypass the structured message protocol.
* Include inline secrets, tokens, or API keys.

```swift theme={null}
// Good: Minimal configuration
let config = BridgeConfiguration(
    hostVersion: "1.0.0",
    capabilities: [...],
    bootstrapScript: """
    window.GBGBridge = window.GBGBridge || {};
    window.GBGBridge.receive = window.GBGBridge.receive || function(){};
    window.GBGBridge.config = { theme: 'dark' };
    """
)

// Bad: Exposes secrets
let config = BridgeConfiguration(
    hostVersion: "1.0.0",
    capabilities: [...],
    bootstrapScript: """
    window.GBGBridge = window.GBGBridge || {};
    window.GBGBridge.apiKey = '\(apiKey)';  // DO NOT DO THIS
    """
)
```

### Frame Isolation

By default, `BridgeWebViewConfigurator` injects the bootstrap script and message handler with `forMainFrameOnly: true`. This means only the top-level frame can access the bridge — iframes (including untrusted third-party content) cannot call `window.webkit.messageHandlers.gbgBridge.postMessage()` or invoke native capabilities.

If your journey architecture requires iframe bridging (e.g., the verification flow runs inside an iframe), you will need to build a custom configurator that sets `forMainFrameOnly: false` and add origin validation in your handlers to ensure only trusted frames can invoke capabilities.

## Message Validation

### Incoming Message Decoding

`BridgeHost` decodes incoming messages using `JSONDecoder`. If a message doesn't conform to the `BridgeMessage` structure, it is rejected and `lastError` is set. Malformed messages never reach handlers or the delegate.

### Action Validation

Handlers are routed by exact string match on the `action` field. Register handlers only for actions you expect. Unexpected actions go to `pendingRequests` where you can inspect and respond to them.

### Data Validation in Handlers

Always validate the `data` payload in your handlers. The web content is a less-trusted zone — treat incoming data the same way you would treat user input.

```swift theme={null}
public func handle(request: BridgeMessage, responder: BridgeResponder) async {
    // Validate required fields
    guard let side = request.payload.data?["side"],
          case .string(let sideValue) = side,
          ["front", "back"].contains(sideValue) else {
        responder.respond(
            status: .error,
            data: nil,
            error: BridgeErrorPayload(
                code: "INVALID_PARAMS",
                message: "Missing or invalid 'side' parameter. Expected 'front' or 'back'.",
                recoverable: true
            )
        )
        return
    }

    // Proceed with validated data
    await performCapture(side: sideValue)
}
```

## Permission Management

### Native Permissions

GBGBridge itself does not request any iOS permissions. Your capability handlers are responsible for requesting and checking permissions as needed.

<Tip>
  Check permission status before performing the operation, and return a clear error if permission is denied.
</Tip>

```swift theme={null}
import AVFoundation

public func handle(request: BridgeMessage, responder: BridgeResponder) async {
    let status = AVCaptureDevice.authorizationStatus(for: .video)

    switch status {
    case .authorized:
        await performCapture(responder: responder)

    case .notDetermined:
        let granted = await AVCaptureDevice.requestAccess(for: .video)
        if granted {
            await performCapture(responder: responder)
        } else {
            responder.respond(
                status: .error,
                data: nil,
                error: BridgeErrorPayload(
                    code: "CAMERA_DENIED",
                    message: "Camera access was denied. Please enable it in Settings.",
                    recoverable: true
                )
            )
        }

    case .denied, .restricted:
        responder.respond(
            status: .error,
            data: nil,
            error: BridgeErrorPayload(
                code: "CAMERA_DENIED",
                message: "Camera access is not available. Please enable it in Settings.",
                recoverable: true
            )
        )

    @unknown default:
        break
    }
}
```

### Info.plist Requirements

Add usage descriptions for every permission your handlers might request:

| Permission    | Key                                   |
| ------------- | ------------------------------------- |
| Camera        | `NSCameraUsageDescription`            |
| NFC           | `NSNFCReaderUsageDescription`         |
| Photo Library | `NSPhotoLibraryUsageDescription`      |
| Location      | `NSLocationWhenInUseUsageDescription` |

Missing usage descriptions cause a runtime crash when the permission is requested.

## Production Checklist

Before shipping your integration:

* [ ] **HTTPS only** — Journey URL uses HTTPS. No global ATS exceptions.
* [ ] **No secrets in bootstrap scripts** — Custom bootstrap scripts contain no API keys or tokens.
* [ ] **Input validation** — All handlers validate incoming `data` payloads.
* [ ] **Permission handling** — Handlers check and request permissions before accessing protected resources.
* [ ] **Info.plist entries** — Usage descriptions for all permissions handlers might request.
* [ ] **Error information** — Error responses do not leak internal implementation details.
* [ ] **Frame policy** — Considered whether `forMainFrameOnly` should be `true` for your use case.
* [ ] **Certificate pinning** — Evaluated whether certificate pinning is required for your security posture.

## Next Steps

* [Troubleshooting Guide](/docs/go-v2/developer-integration/sdks/ios/troubleshooting) — Diagnosing security-related issues
* [Embedding Guide](/docs/go-v2/developer-integration/sdks/ios/embedding) — Secure WebView configuration
* [API Reference](/docs/go-v2/developer-integration/sdks/ios/api-reference) — Configuration and setup API
