Skip to content

BuildNot yet confirmed elsewhere1 publisher3 min readPublished

GoodBarber serves on-device iOS web content from a fixed https origin through iOS 17's proxy API

GoodBarber now serves on-device web content in its iOS apps from https://secure.internal, through a WKWebsiteDataStore proxy API added in iOS 17. A fixed name gives the company's token issuer one origin to allowlist, where the old loopback server needed a wildcard that matched any port on the phone.

The Engineer · Build desk

How we use AISend a correction

Illustration accompanying GoodBarber serves on-device iOS web content from a fixed https origin through iOS 17's proxy API
Generated illustration

What happened

  • Apple's documentation says registering a WKWebView scheme handler for https, a scheme WebKit already handles, raises an exception.
  • GoodBarber's Android engine moved to WebViewAssetLoader and a fixed https origin on July 31, and the token issuer accepted it the same day.
  • Shipping a public certificate's private key for a hostname pointing at 127.0.0.1 was ruled out, a setup Let's Encrypt advises against.

Why it matters

  • exposure While the http://127.0.0.1:* rule stands, a page from any other local server on the same phone counts as an approved parent for the token issuer's page.
  • constraint Because WebKit refuses custom https handlers, a fixed https origin for local files on iOS depends on an API that exists only from iOS 17 onward.
  • decision Every remote service these widgets call has to add https://secure.internal to its allowlist before an iOS widget that depends on it can work.
  • cost Cookies and stored widget data follow the origin, so three serving changes in a year put sessions and saved data under a new key three times.

The first suspect was the HTTP verb. A GoodBarber engineer who looks after the backend of an extension builder the company is piloting wrote: "GET works, POST fails. I spent a morning on the verb. The cause was the page's origin, and the GET had never worked." [7][3] The network connection was fine. The Android test phone did the same thing, and in a browser both calls worked [2]. The post says the widget's story resolves "once the dates make sense" [17]. The available text of the post breaks off mid-sentence at the iOS 17 API [15], before that explanation and before its account of what the new origin broke.

Origin decides more than CORS in this design. A widget that needs a private API key never holds it. It frames a small page from GoodBarber's token issuer, gets a short-lived token, and calls a GoodBarber proxy that keeps the key [6]. The issuer lets only approved origins frame that page, through a CSP frame-ancestors directive [6]. So the origin the native shell gives local files decides whether any of those widgets work at all [6]. The same choice sets secure-context status, which crypto.subtle requires, along with cookie behaviour and where localStorage and IndexedDB data are stored [5]. The builder has not shipped to customers [7].

The second of three serving versions in a year was good work [8]. The iOS team built a real local server, with a request parser, range requests for media, keep-alive and recovery when the listener dies [9]. The shell rewrites the page's cross-origin fetch calls to point at that server, and the server relays them [9]. Loopback is a potentially trustworthy origin, so the pages became secure contexts [9].

The port was the weak point. It is assigned at runtime, so there was no single origin to put in a remote allowlist [10]. On July 30 the token issuer started accepting http://127.0.0.1:* [10]. That is valid CSP. It also matches any port, including any unrelated local server on the phone [10].

WebKit blocks the direct route to a fixed https name. Apple's documentation for setURLSchemeHandler(_:forURLScheme:) says registering a handler for a scheme WebKit already handles, such as https, raises an exception [11]. Android has no such rule. Its shouldInterceptRequest can answer any request, https included, and WebViewAssetLoader packages the pattern with a reserved domain, appassets.androidplatform.net [12]. GoodBarber's Android engine moved to the loader on July 31, and the issuer accepted the new origin the same day [12]. Android had its fixed https origin one day after iOS got a wildcard [18].

The tempting shortcut is a public hostname that resolves to 127.0.0.1, a certificate from a public authority, and the private key shipped inside the app [13]. Let's Encrypt's page on certificates for localhost says not to do it [13]. A key distributed in an app is a compromised key, the certificate may be revoked, and the DNS lookup gives an attacker something to intercept [13]. An offline section would also depend on DNS [13]. GoodBarber instead uses a certificate whose trust is limited to its own WebView, with no public authority involved [14]. iOS 17 added proxyConfigurations to WKWebsiteDataStore, fed by the Network framework [15]. The iOS engine now serves local files from https://secure.internal through it [16].

Two conditions decide whether this design carries over to another app. Pages that need the fixed origin need iOS 17 as a floor, because the API arrived in that release [15]. Every remote service those pages talk to also has to list the new origin, as the token issuer listed each of GoodBarber's earlier ones [10][12]. Each change of origin moves cookies and the storage keyed to it [5]. The post says the breakage from that lands "in places no crash log reaches" [16].

What to watch

  • The rest of the GoodBarber post, which says it explains why the widget's GET quote appeared and what the secure.internal origin broke.
  • Whether the token issuer drops its http://127.0.0.1:* rule once iOS apps serve local content from https://secure.internal.
  • How GoodBarber handles devices below iOS 17, where WKWebsiteDataStore has no proxyConfigurations.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence55
Adoption20
Hype gap0
Incentives30
Confidence55
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    On September 16 the author opened a test widget on an iPhone that made two calls to the same third-party API with the same key: a GET for a quote when the widget opens and a POST for a similarity score from a Compare button.

    ReportedSupportedSource: GoodBarber engineer, dev.to postView cited source
  2. [2]

    The quote appeared but the Compare button returned its failure message telling the user to check their connection; the connection was fine, the author's Android test phone did exactly the same, and in a browser both calls worked.

    ReportedSupportedSource: GoodBarber engineer, dev.to postView cited source
  3. [3]

    "GET works, POST fails. I spent a morning on the verb. The cause was the page's origin, and the GET had never worked."

    ReportedSupportedSource: GoodBarber engineer, dev.to postView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · October 1, 2026

    How do you give local content in a WKWebView a real https origin? (iOS 17)

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

Loading related stories