Skip to content

Let a connection present cookies on the WebSocket handshake - #124

Open
RReverser wants to merge 1 commit into
home-assistant:mainfrom
RReverser:ws-cookies
Open

RReverser wants to merge 1 commit into
home-assistant:mainfrom
RReverser:ws-cookies

Conversation

@RReverser

Copy link
Copy Markdown

An authentication proxy in front of Home Assistant, such as Cloudflare Access, gates every request on the session cookie it issued at login. A caller can send that cookie on REST calls through urlSession:, but nothing in HAKit's API reaches the WebSocket handshake, so the proxy rejects the socket with 401 and the connection never comes up.

HAConnectionInfo now takes an optional cookieStorage, and both engines present its cookies for the WebSocket URL on the handshake.

An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. A caller can send
that cookie on REST calls through `urlSession:`, but nothing in HAKit's API
reaches the WebSocket handshake, so the proxy rejects the socket with 401 and
the connection never comes up.

`HAConnectionInfo` now takes an optional `cookieStorage`, and both engines
present its cookies for the WebSocket URL on the handshake.

@home-assistant home-assistant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @RReverser

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

@home-assistant

Copy link
Copy Markdown

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@home-assistant
home-assistant Bot marked this pull request as draft September 27, 2026 16:42
@RReverser
RReverser marked this pull request as ready for review September 27, 2026 16:44
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies in a store the
native `URLSession`s cannot read, and the webhook session disabled cookies
entirely. So such a server only worked in the frontend, and sensors, location,
widgets and token refresh all got 401. The Android app fixed the same problem
in home-assistant/android#1797 by sharing WebKit's cookie store with its HTTP
client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage and every native session reads from there.
The app group is needed because the extensions and the background webhook
session run in their own processes. The copy is additive: a renewed cookie
replaces the old one by name and expired cookies drop out on their own, so
nothing tracks what the WebView deleted. A cookie the frontend drops early, on
logout for instance, therefore stays usable natively until it expires.

Two gaps remain. The WebSocket handshake gets its cookies through
home-assistant/HAKit#124, and the app will pass the storage to
`HAConnectionInfo` once that ships. The Watch app has its own app-group
container, and no cookies reach it. Android has the same gap, since its jar
skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies in a store the
native `URLSession`s cannot read, and the webhook session disabled cookies
entirely. So such a server only worked in the frontend, and sensors, location,
widgets and token refresh all got 401. The Android app fixed the same problem
in home-assistant/android#1797 by sharing WebKit's cookie store with its HTTP
client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage and every native session reads from there.
The app group is needed because the extensions and the background webhook
session run in their own processes. The copy is additive: a renewed cookie
replaces the old one by name and expired cookies drop out on their own, so
nothing tracks what the WebView deleted. A cookie the frontend drops early, on
logout for instance, therefore stays usable natively until it expires.

Two gaps remain. The WebSocket handshake gets its cookies through
home-assistant/HAKit#124 (independent of this change: the app will pass the
storage to `HAConnectionInfo` in a follow-up once that ships). The Watch app has its own app-group
container, and no cookies reach it. Android has the same gap, since its jar
skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies where native
`URLSession`s cannot read them. So such a server only worked in the frontend,
and sensors, location, widgets and token refresh all got 401. The Android app
fixed the same problem in home-assistant/android#1797 by sharing WebKit's cookie
store with its HTTP client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (the extensions and the background webhook
session run in their own processes) and every native session reads from there.

Two gaps remain. The WebSocket handshake gets its cookies through
home-assistant/HAKit#124 (independent of this change: the app will pass the
storage to `HAConnectionInfo` in a follow-up once that ships). The Watch app has
its own app-group container, and no cookies reach it. Android has the same gap,
since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies where native
`URLSession`s cannot read them. So such a server only worked in the frontend,
and sensors, location, widgets and token refresh all got 401. The Android app
fixed the same problem in home-assistant/android#1797 by sharing WebKit's cookie
store with its HTTP client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (the extensions and the background webhook
session run in their own processes) and every native session reads from there.

Two gaps remain:

1. The WebSocket handshake gets its cookies through home-assistant/HAKit#124
   (independent of this change: the app will pass the storage to
   `HAConnectionInfo` in a follow-up once that ships).
2. The Watch app has its own app-group container, and no cookies reach it.
   Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies where native
`URLSession`s cannot read them. So such a server only worked in the frontend,
and sensors, location, widgets and token refresh all got 401. The Android app
fixed the same problem in home-assistant/android#1797 by sharing WebKit's cookie
store with its HTTP client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (the extensions and the background webhook
session run in their own processes) and every native session reads from there.

Two gaps remain:

1. The WebSocket handshake gets its cookies through home-assistant/HAKit#124
   (independent of this change: the app will pass the storage to
   `HAConnectionInfo` in a follow-up once that ships).
2. The Watch app has its own app-group container, and no cookies reach it.
   Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies where native
`URLSession`s cannot read them. So such a server only worked in the frontend,
and sensors, location, widgets and token refresh all got 401. The Android app
fixed the same problem in home-assistant/android#1797 by sharing WebKit's cookie
store with its HTTP client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (the extensions and the background webhook
session run in their own processes) and every native session reads from there.

Two gaps remain:

1. The WebSocket handshake gets its cookies through home-assistant/HAKit#124
   (independent of this change: the app will pass the storage to
   `HAConnectionInfo` in a follow-up once that ships).
2. The Watch app has its own app-group container, and no cookies reach it.
   Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies where native
`URLSession`s cannot read them. So such a server only worked in the frontend,
and sensors, location, widgets and token refresh all got 401. The Android app
fixed the same problem in home-assistant/android#1797 by sharing WebKit's cookie
store with its HTTP client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (the extensions and the background webhook
session run in their own processes) and every native session reads from there.

Two gaps remain:

1. The WebSocket handshake gets its cookies through home-assistant/HAKit#124
   (independent of this change: the app will pass the storage to
   `HAConnectionInfo` in a follow-up once that ships).
2. The Watch app has its own app-group container, and no cookies reach it.
   Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie it issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies where native
`URLSession`s cannot read them. So such a server only worked in the frontend,
and sensors, location, widgets and token refresh all got 401. The Android app
fixed the same problem in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (the extensions and the background webhook
session run in their own processes) and every native session reads from there.

Two gaps remain:

1. The WebSocket handshake gets its cookies through home-assistant/HAKit#124
   (independent of this change: the app will pass the storage to
   `HAConnectionInfo` in a follow-up once that ships).
2. The Watch app has its own app-group container, and no cookies reach it.
   Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
An authentication proxy in front of Home Assistant, such as Cloudflare Access,
gates every request on the session cookie issued at login. The frontend gets
that cookie through the WebView, but WebKit keeps its cookies where native
`URLSession`s cannot read them. So the frontend worked and nothing else did:
sensors, location, widgets and token refresh all got 401. The Android app fixed
the same problem in home-assistant/android#1797 by sharing its WebView's cookie
store with its HTTP client.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Home Assistant behind an authentication proxy such as Cloudflare Access works
in the app's frontend only. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, which was the remaining outlier out of the three supported
platforms (web, Android and iOS).

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets and token refresh all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Home Assistant behind an authentication proxy such as Cloudflare Access works
in the app's frontend only. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets and token refresh all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Behind an authentication proxy such as Cloudflare Access, the app worked in its
frontend only. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets and token refresh all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets and token refresh all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets and token refresh all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets and token refresh all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets and token refresh all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets and token refresh all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets, token refresh and even onboarding's own
code exchange, right after the WebView login that produced the cookie, all got
401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets, token refresh and even onboarding's own
code exchange, right after the WebView login that produced the cookie, all got
401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets, token refresh and even onboarding's own
code exchange, right after the WebView login that produced the cookie, all got
401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets, the webhook reachability check in
Settings, token refresh and even onboarding's own code exchange, right after
the WebView login that produced the cookie, all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets, the webhook reachability check in
Settings, token refresh and even onboarding's own code exchange, right after
the WebView login that produced the cookie, all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native `URLSession`s cannot read them. So the frontend worked and nothing
else did: sensors, location, widgets, the webhook reachability check in
Settings, token refresh and even onboarding's own code exchange, right after
the WebView login that produced the cookie, all got 401.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native session
reads from there.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Only the app's frontend worked behind an authentication proxy such as
Cloudflare Access. The Android app had the same problem
(home-assistant/android#1708) and fixed it in home-assistant/android#1797 by
sharing its WebView's cookie store with its HTTP client. This change fixes it
for iOS as well, the last client where such a setup did not work.

Such a proxy gates every request on the session cookie issued at login. The
frontend gets that cookie through the WebView, but WebKit keeps its cookies
where native requests cannot read them. So the frontend worked and nothing else
did: sensors, location, widgets, Assist voice replies, camera streams, token
refresh and the connection diagnostics all got 401, and so did onboarding's own
code exchange right after the WebView login that produced the cookie.

iOS offers no way to share WebKit's store, so `WebViewCookieMirror` copies it
into an app-group cookie storage (`.shared` is per process, and the extensions
and the background webhook session are separate ones) and every native request
presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 27, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 28, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 28, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 28, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 28, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.
RReverser added a commit to RReverser/hass-ios that referenced this pull request Sep 28, 2026
Without this fix, the iOS app fails to load anything except frontend behind
authentication proxies such as Cloudflare Access.

Such auth proxies gate every request on the session cookie issued at login.
The frontend gets that cookie through the WebView, but WebKit keeps its
cookies where native requests cannot read them. So anything besides the
frontend - sensors, location, widgets, Assist voice replies, camera streams,
token refresh, connection diagnostics and even onboarding's own code exchange -
got the 401 unauthorised error.

The Android app had the same problem (home-assistant/android#1708) and fixed it
couple of years ago in home-assistant/android#1797 by sharing its WebView's
cookie store with its HTTP client. This change implements the analogous fix
for iOS as well, the last client where such a setup did not work.

iOS offers no way to directly share the WebKit's store, so
`WebViewCookieMirror` copies it into an app-group cookie storage and every
native request presents it, including media that AVFoundation fetches itself.

Two gaps remain:

1. The WebSocket handshake still does not receive cookies. A follow-up will fix
   that once home-assistant/HAKit#124 has landed.
2. The Watch app never receives cookies either, because it has an app-group
   container of its own. Android has the same gap, since its jar skips Wear OS.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant