Auth logout URL, auth proxy

This commit is contained in:
binwiederhier
2026-01-22 20:19:59 -05:00
parent 46cb9f2b41
commit b67ffa4f5f
11 changed files with 104 additions and 35 deletions

View File

@@ -20,4 +20,7 @@ var config = {
web_push_public_key: "",
disallowed_topics: ["docs", "static", "file", "app", "account", "settings", "signup", "login", "v1"],
config_hash: "dev", // Placeholder for development; actual value is generated server-side
auth_mode: "", // "proxy" if auth-user-header is set, empty otherwise
auth_logout_url: "", // URL to redirect to on logout (only for proxy auth)
username: "", // Authenticated username (for proxy auth)
};

View File

@@ -16,6 +16,7 @@ import {
withBasicAuth,
withBearerAuth,
} from "./utils";
import config from "./config";
import session from "./Session";
import subscriptionManager from "./SubscriptionManager";
import prefs from "./Prefs";
@@ -341,7 +342,12 @@ class AccountApi {
async sync() {
try {
if (!session.token()) {
// For proxy auth, store the username from config if not already in session
if (config.auth_mode === "proxy" && config.username && !session.exists()) {
console.log(`[AccountApi] Proxy auth: storing session for user ${config.username}`);
await session.store(config.username, ""); // Empty token for proxy auth
}
if (!session.exists()) {
return null;
}
console.log(`[AccountApi] Syncing account`);

View File

@@ -3,6 +3,10 @@ import Dexie from "dexie";
/**
* Manages the logged-in user's session and access token.
* The session replica is stored in IndexedDB so that the service worker can access it.
*
* For proxy authentication (when config.auth_mode === "proxy"), the token will be empty
* since authentication is handled by the proxy. In this case, store(username, "") is called
* with an empty token, and exists() returns true based on the username alone.
*/
class Session {
constructor() {
@@ -53,7 +57,7 @@ class Session {
}
exists() {
return this.username() && this.token();
return !!this.username();
}
username() {

View File

@@ -139,6 +139,17 @@ const ProfileIcon = () => {
};
const handleLogout = async () => {
// For proxy auth, redirect to the logout URL if configured
if (config.auth_mode === "proxy") {
if (config.auth_logout_url) {
await db().delete();
localStorage.removeItem("user");
localStorage.removeItem("token");
window.location.href = config.auth_logout_url;
}
return;
}
// Standard logout
try {
await accountApi.logout();
await db().delete();
@@ -147,6 +158,9 @@ const ProfileIcon = () => {
}
};
// Determine if logout button should be shown
const showLogout = config.auth_mode !== "proxy" || config.auth_logout_url;
return (
<>
{session.exists() && (
@@ -178,12 +192,14 @@ const ProfileIcon = () => {
</ListItemIcon>
{t("action_bar_profile_settings")}
</MenuItem>
<MenuItem onClick={handleLogout}>
<ListItemIcon>
<Logout fontSize="small" />
</ListItemIcon>
{t("action_bar_profile_logout")}
</MenuItem>
{showLogout && (
<MenuItem onClick={handleLogout}>
<ListItemIcon>
<Logout fontSize="small" />
</ListItemIcon>
{t("action_bar_profile_logout")}
</MenuItem>
)}
</PopupMenu>
</>
);

View File

@@ -1,5 +1,5 @@
import * as React from "react";
import { useState } from "react";
import { useState, useEffect } from "react";
import { Typography, TextField, Button, Box, IconButton, InputAdornment } from "@mui/material";
import WarningAmberIcon from "@mui/icons-material/WarningAmber";
import { NavLink } from "react-router-dom";
@@ -18,6 +18,13 @@ const Login = () => {
const [password, setPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
// Redirect to app if using proxy authentication
useEffect(() => {
if (config.auth_mode === "proxy") {
window.location.href = routes.app;
}
}, []);
const handleSubmit = async (event) => {
event.preventDefault();
const user = { username, password };