In the settings of the admin only, add https://digital-land.org/osticket/scp/profile.php#preferences and below it should be the logout.

I'm using osticket and kotlin jetpack compose.
MainActivity.kt:
package com.example.osticket

import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.webkit.CookieManager
import android.webkit.WebStorage
import android.webkit.WebView
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.navigation.NavController
import androidx.navigation.compose.*
import com.example.osticket.ui.theme.OsticketTheme

class MainActivity : ComponentActivity() {
    private lateinit var loginStateManager: LoginStateManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()

        loginStateManager = LoginStateManager(this)

        CookieManager.getInstance().apply {
            setAcceptCookie(true)
        }

        setContent {
            OsticketTheme {
                Surface(color = MaterialTheme.colorScheme.background) {
                    val navController = rememberNavController()
                    NavHost(
                        navController = navController,
                        startDestination = when {
                            loginStateManager.isLoggedIn() -> {
                                if (loginStateManager.isAdmin()) "admin_dashboard" else "user_dashboard"
                            }
                            else -> "login"
                        }
                    ) {
                        composable("login") {
                            LoginScreen(onLoginSuccess = { isAdmin ->
                                loginStateManager.setLoggedIn(true, isAdmin)
                                navController.navigate(if (isAdmin) "admin_dashboard" else "user_dashboard") {
                                    popUpTo("login") { inclusive = true }
                                }
                            })
                        }
                        composable("admin_dashboard") {
                            DashboardScreen(
                                isAdmin = true,
                                onLogout = {
                                    performLogout(navController)
                                }
                            )
                        }
                        composable("user_dashboard") {
                            DashboardScreen(
                                isAdmin = false,
                                onLogout = {
                                    performLogout(navController)
                                }
                            )
                        }
                    }
                }
            }
        }
    }

    private fun performLogout(navController: NavController) {
        // Clear all data
        loginStateManager.clearAllData()

        // Navigate back to login
        navController.navigate("login") {
            popUpTo(0) { inclusive = true }
        }

        // Recreate WebView instance to ensure clean state
        WebView(this).destroy()
    }

    override fun onDestroy() {
        CookieManager.getInstance().flush()
        super.onDestroy()
    }
}

class LoginStateManager(private val context: Context) {
    private val prefs: SharedPreferences = context.getSharedPreferences(
        "osticket_prefs",
        Context.MODE_PRIVATE
    )

    fun setLoggedIn(isLoggedIn: Boolean, isAdmin: Boolean) {
        prefs.edit()
            .putBoolean(KEY_IS_LOGGED_IN, isLoggedIn)
            .putBoolean(KEY_IS_ADMIN, isAdmin)
            .apply()
    }

    fun isLoggedIn(): Boolean = prefs.getBoolean(KEY_IS_LOGGED_IN, false)

    fun isAdmin(): Boolean = prefs.getBoolean(KEY_IS_ADMIN, false)

    fun clearAllData() {
        // Clear SharedPreferences
        prefs.edit().clear().apply()

        // Clear Cookies
        CookieManager.getInstance().apply {
            removeAllCookies(null)
            flush()
        }

        // Clear WebView data
        WebView(context).apply {
            clearCache(true)
            clearFormData()
            clearHistory()
            clearSslPreferences()
        }

        // Clear WebStorage
        WebStorage.getInstance().deleteAllData()

        // Clear app cache directory
        try {
            context.cacheDir?.deleteRecursively()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    companion object {
        private const val KEY_IS_LOGGED_IN = "is_logged_in"
        private const val KEY_IS_ADMIN = "is_admin"
    }
}

LoginScreen.kt:
package com.example.osticket

import CustomWebView
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

@Composable
fun LoginScreen(onLoginSuccess: (Boolean) -> Unit) {
    var showWebView by remember { mutableStateOf(false) }
    var isAdminLogin by remember { mutableStateOf(false) }

    if (!showWebView) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(Color(0xFFEEEEEE))
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Text(
                text = "OSTicket Login",
                style = MaterialTheme.typography.headlineMedium,
                modifier = Modifier.padding(bottom = 32.dp)
            )

            Button(
                onClick = {
                    isAdminLogin = false
                    showWebView = true
                },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(bottom = 16.dp)
                    .background(Color(0xFFEEEEEE))
            ) {
                Text("Login as User", color = Color.Black)
            }

            Button(
                onClick = {
                    isAdminLogin = true
                    showWebView = true
                },
                modifier = Modifier.fillMaxWidth().background(Color(0xFFEEEEEE))
            ) {
                Text("Login as Agent/Admin", color = Color.Black)
            }
        }
    } else {
        CustomWebView(
            url = if (isAdminLogin) {
                "https://digital-land.org/osticket/scp/index.php"
            } else {
                "https://digital-land.org/osticket/login.php"
            },
            onUrlChange = { newUrl ->
                if (isAdminLogin && newUrl.startsWith("https://digital-land.org/osticket/scp/index.php")) {
                    onLoginSuccess(true)
                } else if (!isAdminLogin && newUrl.startsWith("https://digital-land.org/osticket/tickets.php")) {
                    onLoginSuccess(false)
                }
            }
        )
    }
}
DashboardScreen.kt:
package com.example.osticket

import WebViewScreen
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController

import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.unit.dp

sealed class Screen(val route: String, val label: String, val icon: ImageVector) {
    // Admin/Agent screens
    object AdminTickets : Screen("admin_tickets", "Tickets", Icons.Default.List)
    object Tasks : Screen("tasks", "Tasks", Icons.Default.Check)
    object Users : Screen("users", "Users", Icons.Default.Person)
    object Other : Screen("other", "Settings", Icons.Default.Settings)

    // User screens
    object UserTickets : Screen("user_tickets", "My Tickets", Icons.Default.List)
    object UserProfile : Screen("user_profile", "Profile", Icons.Default.Person)
    object UserSettings : Screen("user_settings", "Settings", Icons.Default.Settings)
}

@Composable
fun DashboardScreen(
    isAdmin: Boolean,
    onLogout: () -> Unit
) {
    val navController = rememberNavController()
    val items = if (isAdmin) {
        listOf(
            Screen.AdminTickets,
            Screen.Tasks,
            Screen.Users,
            Screen.Other
        )
    } else {
        listOf(
            Screen.UserTickets,
            Screen.UserProfile,
            Screen.UserSettings
        )
    }

    Scaffold(
        bottomBar = {
            BottomNavigationBar(navController = navController, items = items)
        }
    ) { innerPadding ->
        NavHost(
            navController = navController,
            startDestination = if (isAdmin) Screen.AdminTickets.route else Screen.UserTickets.route,
            modifier = Modifier.padding(innerPadding)
        ) {
            if (isAdmin) {
                // Admin/Agent routes
                composable(Screen.AdminTickets.route) {
                    WebViewScreen(url = "https://digital-land.org/osticket/scp/index.php")
                }
                composable(Screen.Tasks.route) {
                    WebViewScreen(url = "https://digital-land.org/osticket/scp/tasks.php")
                }
                composable(Screen.Users.route) {
                    WebViewScreen(url = "https://digital-land.org/osticket/scp/users.php")
                }
                composable(Screen.Other.route) {
                    SettingsScreen(isAdmin = true, onLogout = onLogout)
                }
            } else {
                // User routes
                composable(Screen.UserTickets.route) {
                    WebViewScreen(url = "https://digital-land.org/osticket/tickets.php")
                }
                composable(Screen.UserProfile.route) {
                    WebViewScreen(url = "https://digital-land.org/osticket/profile.php")
                }
                composable(Screen.UserSettings.route) {
                    SettingsScreen(isAdmin = false, onLogout = onLogout)
                }
            }
        }
    }
}

@Composable
fun BottomNavigationBar(navController: NavController, items: List<Screen>) {
    NavigationBar {
        val currentRoute = currentRoute(navController)
        items.forEach { screen ->
            NavigationBarItem(
                icon = { Icon(screen.icon, contentDescription = screen.label) },
                label = { Text(screen.label) },
                selected = currentRoute == screen.route,
                onClick = {
                    if (currentRoute != screen.route) {
                        navController.navigate(screen.route) {
                            // Avoid multiple copies of the same destination
                            launchSingleTop = true
                            restoreState = true
                            // Pop up to the start destination of the graph to avoid building up a large stack
                            popUpTo(navController.graph.startDestinationId) {
                                saveState = true
                            }
                        }
                    }
                }
            )
        }
    }
}

@Composable
fun currentRoute(navController: NavController): String? {
    val navBackStackEntry = navController.currentBackStackEntryAsState()
    return navBackStackEntry.value?.destination?.route
}



@Composable
fun SettingsScreen(
    isAdmin: Boolean,
    onLogout: () -> Unit
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        Text(
            text = "Settings",
            style = MaterialTheme.typography.headlineMedium
        )

        // Add any other settings options here

        Spacer(modifier = Modifier.weight(1f))

        Button(
            onClick = {
                // Perform logout actions
                onLogout()
            },
            colors = ButtonDefaults.buttonColors(
                containerColor = MaterialTheme.colorScheme.error
            ),
            modifier = Modifier
                .fillMaxWidth()
                .padding(bottom = 16.dp)
        ) {
            Text("Logout")
        }
    }
}

CustomWebView.kt:
import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.util.Log
import android.view.ViewGroup
import android.webkit.ConsoleMessage
import android.webkit.CookieManager
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun CustomWebView(
    url: String,
    onUrlChange: (String) -> Unit = {},
    onLoadingStateChange: (Boolean) -> Unit = {},
    onCookiesReceived: (List<Cookie>) -> Unit = {},
    onError: (String) -> Unit = {},
    onPageFinished: () -> Unit = {},
    enableJavaScript: Boolean = true,
    allowZoom: Boolean = false,
    userAgent: String? = null
) {
    val context = LocalContext.current
    val cookieManager = CookieManager.getInstance().apply {
        setAcceptCookie(true)
    }

    // Remember the WebView to preserve its state across recompositions
    val webView = remember {
        WebView(context).apply {
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )

            // Set third party cookies for this specific WebView instance
            cookieManager.setAcceptThirdPartyCookies(this, true)

            // Initialize WebViewClient with overridden methods
            webViewClient = object : WebViewClient() {
                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                    super.onPageStarted(view, url, favicon)
                    onLoadingStateChange(true)
                    url?.let { onUrlChange(it) }
                }

                override fun onPageFinished(view: WebView?, url: String?) {
                    super.onPageFinished(view, url)
                    onLoadingStateChange(false)
                    getCurrentCookies(view)
                    onPageFinished()
                }

                override fun shouldOverrideUrlLoading(
                    view: WebView?,
                    request: WebResourceRequest?
                ): Boolean {
                    request?.url?.toString()?.let { onUrlChange(it) }
                    return false
                }

                override fun onReceivedError(
                    view: WebView?,
                    request: WebResourceRequest?,
                    error: WebResourceError?
                ) {
                    error?.description?.toString()?.let { onError(it) }
                }

                private fun getCurrentCookies(view: WebView?) {
                    view?.url?.let { currentUrl ->
                        val cookies = cookieManager.getCookie(currentUrl)?.split(";")?.mapNotNull { cookieString ->
                            val parts = cookieString.trim().split("=", limit = 2)
                            if (parts.size == 2) {
                                Cookie(parts[0], parts[1])
                            } else {
                                null
                            }
                        } ?: emptyList()
                        onCookiesReceived(cookies)
                    }
                }
            }

            webChromeClient = object : WebChromeClient() {
                override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean {
                    Log.d(
                        "WebView",
                        "${consoleMessage?.message()} -- From line ${consoleMessage?.lineNumber()} of ${consoleMessage?.sourceId()}"
                    )
                    return true
                }

                override fun onProgressChanged(view: WebView?, newProgress: Int) {
                    super.onProgressChanged(view, newProgress)
                    onLoadingStateChange(newProgress < 100)
                }
            }

            // Configure WebView settings
            settings.apply {
                javaScriptEnabled = enableJavaScript
                domStorageEnabled = true
                javaScriptCanOpenWindowsAutomatically = true
                loadWithOverviewMode = true
                useWideViewPort = true
                allowContentAccess = true
                allowFileAccess = true
                builtInZoomControls = allowZoom
                displayZoomControls = false
                setSupportZoom(allowZoom)
                mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
                defaultTextEncodingName = "utf-8"
                cacheMode = WebSettings.LOAD_DEFAULT // Enable caching
                userAgent?.let { userAgentString = it }

                // Enable database
                databaseEnabled = true
            }

            // Load the initial URL once
            loadUrl(url)
        }
    }

    // Modified DisposableEffect to preserve state
    DisposableEffect(Unit) {
        onDispose {
            webView.stopLoading()
            // Don't clear cache or cookies
            webView.loadUrl("about:blank")
            // Only remove views, don't destroy the WebView
            webView.removeAllViews()
        }
    }

    // Embed the WebView into the Compose UI
    AndroidView(
        factory = { webView },
        update = { /* No-op to prevent reloading */ }
    )
}



// Data class for cookies
data class Cookie(
    val name: String,
    val value: String
)

// Example usage:
@Composable
fun WebViewScreen(url: String) {
    var currentUrl by remember { mutableStateOf("") }
    var isLoading by remember { mutableStateOf(true) }
    var cookies by remember { mutableStateOf<List<Cookie>>(emptyList()) }
    var error by remember { mutableStateOf<String?>(null) }

    Column {
        if (isLoading) {
            LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
        }

        error?.let { errorMessage ->
            Text(
                text = errorMessage,
                modifier = Modifier.padding(16.dp)
            )
        }

        CustomWebView(
            url = url,
            onUrlChange = { newUrl ->
                currentUrl = newUrl
                // Handle URL change
            },
            onLoadingStateChange = { loading ->
                isLoading = loading
            },
            onCookiesReceived = { newCookies ->
                cookies = newCookies
                // Handle cookies
            },
            onError = { errorMessage ->
                error = errorMessage
            },
            onPageFinished = {
                // Handle page load completion
            },
            enableJavaScript = true,
            allowZoom = false,
        )
    }
}