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

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
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [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.
- [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.
- [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."
- [4]
GoodBarber is an app builder for native iOS and Android apps; some sections are web content (owner custom code, HTML widgets, extensions) whose files live on the device so the section opens offline, and on iOS they are displayed in a WKWebView.
- [5]
How the local files are served decides whether the page is a secure context (a prerequisite for APIs such as crypto.subtle) and sets the origin seen by CORS and CSP checks, cookie behaviour, and where localStorage and IndexedDB data are stored; changing the serving mechanism changes all of that.
- [6]
In GoodBarber's extension builder, a widget needing a private API key never holds it: the page frames a small page served by the company's token issuer, gets a short-lived token, and calls a company proxy that keeps the key. The issuer lets only approved origins frame its page through a CSP frame-ancestors directive, so the origin the native shell gives its local files decides whether any of those widgets can work at all.
- [7]
The author looks after the backend of an extension builder GoodBarber is piloting; the builder has not shipped to customers and the phones in the story are the author's own test devices.
- [8]
GoodBarber went through three versions of its local-content serving mechanism in one year.
- [9]
In the second version the iOS team built a real local server with a request parser, range requests for media, keep-alive and recovery when the listener dies; it relays the page's cross-origin fetch calls, which the shell rewrites towards it. Loopback is a potentially trustworthy origin, so the page became a secure context.
- [10]
The loopback server's port was assigned at runtime, leaving no single origin for a remote allowlist. On July 30 the token issuer started accepting http://127.0.0.1:*, which is valid CSP and accepts any port, including any unrelated local server on the phone.
- [11]
Apple's documentation for setURLSchemeHandler(_:forURLScheme:) says registering a handler for a scheme WebKit already handles, such as https, raises an exception.
- [12]
On Android, shouldInterceptRequest lets an app answer any request including https, and WebViewAssetLoader packages the pattern with the reserved domain appassets.androidplatform.net. GoodBarber's Android engine moved from file:// to that loader on July 31, gaining a fixed https origin, and the issuer accepted it the same day.
- [13]
The shortcut of a public hostname resolving to 127.0.0.1, a public-authority certificate and the private key shipped in the app was rejected: Let's Encrypt's page on certificates for localhost says don't; a key distributed in an app is compromised, the certificate may be revoked, the DNS lookup gives an attacker something to intercept, and the offline section would depend on DNS.
- [14]
GoodBarber could use a certificate whose trust was limited to its own WebView, without recognition from a public authority.
- [15]
iOS 17 added proxyConfigurations to WKWebsiteDataStore, fed by a proxy configuration from the Network framework.
- [16]
GoodBarber's iOS engine now serves local files from a fixed https://secure.internal using the proxy API that arrived in iOS 17; the post says changing an origin breaks things "in places no crash log reaches".
- [17]
The post says the widget comes back at the end, "once the dates make sense."
- [18]
GoodBarber's Android engine got its fixed https origin accepted one day after the token issuer began accepting the iOS loopback wildcard.
Sources
1 independent publisher whose own reporting we read for this story.
- dev.toHow do you give local content in a WKWebView a real https origin? (iOS 17)
1 article · October 1, 2026
Topics and entities
Follow any of these and your For You feed starts watching them — no settings page required.
Topics
- WebView local content originsFollow
- Mobile App SecurityFollow
- Content Security Policy EnforcementFollow
Entities
- GoodBarberFollow
- AppleFollow
- WKWebViewFollow
- iOS 17Follow
- WebViewAssetLoaderFollow
- Let's EncryptFollow