diff --git a/keyserver/src/session/cookies.js b/keyserver/src/session/cookies.js
--- a/keyserver/src/session/cookies.js
+++ b/keyserver/src/session/cookies.js
@@ -787,7 +787,7 @@
   return {
     domain: domainAsURL.hostname,
     path: basePath,
-    httpOnly: true,
+    httpOnly: false,
     secure: https,
     maxAge: cookieLifetime,
     sameSite: 'Strict',
diff --git a/lib/types/keyserver-types.js b/lib/types/keyserver-types.js
--- a/lib/types/keyserver-types.js
+++ b/lib/types/keyserver-types.js
@@ -7,11 +7,8 @@
 import type { ConnectionInfo } from './socket-types.js';
 import { tShape, tPlatformDetails } from '../utils/validation-utils.js';
 
-// Once we start using the cookie field on web,
-// the cookie field should be mandatory, of type ?string.
-// See https://linear.app/comm/issue/ENG-4347/stop-using-browser-cookies
 export type KeyserverInfo = {
-  +cookie?: ?string,
+  +cookie: ?string,
   +sessionID?: ?string,
   +updatesCurrentAsOf: number, // millisecond timestamp
   +urlPrefix: string,
diff --git a/lib/utils/cookie-utils.js b/lib/utils/cookie-utils.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/cookie-utils.js
@@ -0,0 +1,14 @@
+// @flow
+
+function parseCookies(header: string): { +[string]: string } {
+  const values = header.split(';').map(v => v.split('='));
+
+  const cookies = {};
+  for (const [key, value] of values) {
+    cookies[decodeURIComponent(key.trim())] = decodeURIComponent(value.trim());
+  }
+
+  return cookies;
+}
+
+export { parseCookies };
diff --git a/native/redux/default-state.js b/native/redux/default-state.js
--- a/native/redux/default-state.js
+++ b/native/redux/default-state.js
@@ -74,6 +74,7 @@
   keyserverStore: {
     keyserverInfos: {
       [ashoatKeyserverID]: {
+        cookie: null,
         updatesCurrentAsOf: 0,
         urlPrefix: defaultURLPrefix,
         connection: defaultConnectionInfo,
diff --git a/web/redux/default-state.js b/web/redux/default-state.js
--- a/web/redux/default-state.js
+++ b/web/redux/default-state.js
@@ -77,6 +77,7 @@
   keyserverStore: {
     keyserverInfos: {
       [ashoatKeyserverID]: {
+        cookie: null,
         updatesCurrentAsOf: 0,
         urlPrefix: isDev
           ? 'http://localhost:3000/comm'
diff --git a/web/redux/persist.js b/web/redux/persist.js
--- a/web/redux/persist.js
+++ b/web/redux/persist.js
@@ -18,10 +18,12 @@
   KeyserverInfo,
   KeyserverStore,
 } from 'lib/types/keyserver-types.js';
+import { cookieTypes } from 'lib/types/session-types.js';
 import {
   defaultConnectionInfo,
   type ConnectionInfo,
 } from 'lib/types/socket-types.js';
+import { parseCookies } from 'lib/utils/cookie-utils.js';
 import { isDev } from 'lib/utils/dev-utils.js';
 import {
   generateIDSchemaMigrationOpsForDrafts,
@@ -134,6 +136,33 @@
     ...state,
     integrityStore: { threadHashes: {}, threadHashingStatus: 'starting' },
   }),
+  [7]: async (state: AppState): Promise<AppState> => {
+    if (!document.cookie) {
+      return state;
+    }
+
+    const params = parseCookies(document.cookie);
+    let cookie = null;
+    if (params[cookieTypes.USER]) {
+      cookie = `${cookieTypes.USER}=${params[cookieTypes.USER]}`;
+    } else if (params[cookieTypes.ANONYMOUS]) {
+      cookie = `${cookieTypes.ANONYMOUS}=${params[cookieTypes.ANONYMOUS]}`;
+    }
+
+    return {
+      ...state,
+      keyserverStore: {
+        ...state.keyserverStore,
+        keyserverInfos: {
+          ...state.keyserverStore.keyserverInfos,
+          [ashoatKeyserverID]: {
+            ...state.keyserverStore.keyserverInfos[ashoatKeyserverID],
+            cookie,
+          },
+        },
+      },
+    };
+  },
 };
 
 const persistWhitelist = [
@@ -246,7 +275,7 @@
     { debug: isDev },
     migrateStorageToSQLite,
   ): any),
-  version: 6,
+  version: 7,
   transforms: [keyserverStoreTransform],
 };