Skip to content

[Android] incognito globally clears the app-wide CookieManager store #3988

Description

@Preeternal

Bug description:

On Android, mounting a WebView with incognito={true} clears the global android.webkit.CookieManager store:

override fun setIncognito(view: RNCWebViewWrapper, value: Boolean) {
// Don't do anything when incognito is disabled
if (!value) {
return
}
val webView = view.webView
// Remove all previous cookies
CookieManager.getInstance().removeAllCookies(null)

This cookie store is shared with regular WebViews and can also be used by React Native networking and native cookie-management libraries.

As a result, opening a single incognito WebView may remove unrelated application cookies, including authentication cookies used by Fetch/Axios. This can unexpectedly log the user out of the whole application.

removeAllCookies(null) is also asynchronous, but its completion is currently not observed.

To Reproduce:

The issue can be reproduced with @react-native-cookies/cookies, which reads and writes the same Android cookie store:

import React, {useState} from 'react';
import {Button, View} from 'react-native';
import CookieManager from '@react-native-cookies/cookies';
import {WebView} from 'react-native-webview';

const url = 'https://example.com';

export default function App() {
  const [showIncognito, setShowIncognito] = useState(false);

  const reproduce = async () => {
    await CookieManager.clearAll();

    await CookieManager.set(url, {
      name: 'session',
      value: 'authenticated',
      domain: 'example.com',
      path: '/',
    });

    console.log('Before:', await CookieManager.get(url));
    // Contains the "session" cookie.

    setShowIncognito(true);

    setTimeout(async () => {
      console.log('After:', await CookieManager.get(url));
      // The "session" cookie is gone.
    }, 1000);
  };

  return (
    <View style={{flex: 1}}>
      <Button title="Reproduce" onPress={reproduce} />

      {showIncognito && (
        <WebView
          incognito
          source={{uri: url}}
          style={{flex: 1}}
        />
      )}
    </View>
  );
}

The same effect can be observed when the cookie is created by an authenticated React Native network request: subsequent requests no longer receive the cookie after the incognito WebView is mounted.

Expected behavior:
An incognito WebView should use an isolated, non-persistent cookie store.
Creating or destroying it should not modify cookies belonging to regular WebViews, React Native networking, or the application's default cookie store.

Possible direction:
AndroidX WebKit provides isolated profiles on WebView providers supporting WebViewFeature.MULTI_PROFILE.
A possible implementation would be:
Create a dedicated temporary profile for the incognito WebView.
Assign it with WebViewCompat.setProfile() before the WebView is otherwise used.
Delete the profile when the WebView is destroyed.

References:
https://developer.android.com/reference/androidx/webkit/Profile
https://developer.android.com/reference/androidx/webkit/ProfileStore
https://developer.android.com/reference/androidx/webkit/WebViewCompat#setProfile(android.webkit.WebView,java.lang.String)

When MULTI_PROFILE is unavailable, incognito should not silently delete the app-wide cookie store. A non-destructive fallback, an explicit opt-in to the legacy behavior, or a clear unsupported-feature warning would be preferable to implicit global data loss.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions