From ec621bf55aefda6649ce49d7ece6065ab2c54368 Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Sat, 8 Nov 2025 18:04:46 +0000
Subject: feat(mobile): add custom headers configuration in sign-in screen
 (#2103)

* feat(mobile): add custom headers configuration in sign-in screen

Add ability for mobile app users to configure custom HTTP headers that are
sent with every API request. This enables users to add authentication headers,
proxy headers, or other custom headers required by their server setup.

Changes:
- Add customHeaders field to mobile app settings schema
- Create CustomHeadersModal component for managing headers
- Update sign-in screen with link to configure custom headers
- Modify tRPC provider to merge custom headers with Authorization header

The custom headers are stored securely in the app settings and persist
across sessions.

* fix keyboard

* add custom headers to other callsites

---------

Co-authored-by: Claude <noreply@anthropic.com>
---
 apps/mobile/app/signin.tsx | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

(limited to 'apps/mobile/app/signin.tsx')

diff --git a/apps/mobile/app/signin.tsx b/apps/mobile/app/signin.tsx
index 4f74c331..3dc41a0c 100644
--- a/apps/mobile/app/signin.tsx
+++ b/apps/mobile/app/signin.tsx
@@ -7,6 +7,7 @@ import {
   View,
 } from "react-native";
 import { Redirect, useRouter } from "expo-router";
+import { CustomHeadersModal } from "@/components/CustomHeadersModal";
 import Logo from "@/components/Logo";
 import { TailwindResolver } from "@/components/TailwindResolver";
 import { Button } from "@/components/ui/Button";
@@ -31,6 +32,8 @@ export default function Signin() {
   const [tempServerAddress, setTempServerAddress] = useState(
     "https://cloud.karakeep.app",
   );
+  const [isCustomHeadersModalVisible, setIsCustomHeadersModalVisible] =
+    useState(false);
 
   const emailRef = useRef<string>("");
   const passwordRef = useRef<string>("");
@@ -79,6 +82,10 @@ export default function Signin() {
     return <Redirect href="dashboard" />;
   }
 
+  const handleSaveCustomHeaders = (headers: Record<string, string>) => {
+    setSettings({ ...settings, customHeaders: headers });
+  };
+
   const onSignin = () => {
     if (!tempServerAddress) {
       setError("Server address is required");
@@ -184,6 +191,17 @@ export default function Signin() {
                 </Button>
               </View>
             )}
+            <Pressable
+              onPress={() => setIsCustomHeadersModalVisible(true)}
+              className="mt-1"
+            >
+              <Text className="text-xs text-gray-500 underline">
+                Configure Custom Headers{" "}
+                {settings.customHeaders &&
+                  Object.keys(settings.customHeaders).length > 0 &&
+                  `(${Object.keys(settings.customHeaders).length})`}
+              </Text>
+            </Pressable>
           </View>
           {loginType === LoginType.Password && (
             <>
@@ -264,6 +282,12 @@ export default function Signin() {
           </Pressable>
         </View>
       </TouchableWithoutFeedback>
+      <CustomHeadersModal
+        visible={isCustomHeadersModalVisible}
+        customHeaders={settings.customHeaders || {}}
+        onClose={() => setIsCustomHeadersModalVisible(false)}
+        onSave={handleSaveCustomHeaders}
+      />
     </KeyboardAvoidingView>
   );
 }
-- 
cgit v1.2.3-70-g09d2

