Sign out also ends the Authentik SSO session (RP-Initiated Logout)
Previously logout only destroyed our own session -- someone who
signed in via Authentik stayed logged into Authentik itself, so
"Sign in with Authentik" again would silently re-authenticate with
no prompt.
Session now tracks authMethod ("local" | "oidc") and, for OIDC
sessions, the raw id_token (needed as id_token_hint at logout time).
New GET /api/auth/oidc/logout redirects through Authentik's
end_session_endpoint (openid-client's buildEndSessionUrl, not
hand-rolled) before landing back on /. Must be a full-page navigation
-- Authentik needs a real browser request to clear its own session
cookie, a fetch() wouldn't do that. Local sessions still use the
existing POST /api/auth/logout unchanged.
Confirmed Authentik has no dedicated post_logout_redirect_uri
allowlist field by checking the provider's DB schema directly before
implementing, rather than assuming.
Closes #19.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,24 +1,24 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { me } from "./api";
|
||||
import { me, type Me } from "./api";
|
||||
import { Login } from "./pages/Login";
|
||||
import { Dashboard } from "./pages/Dashboard";
|
||||
|
||||
export default function App() {
|
||||
const [username, setUsername] = useState<string | null>(null);
|
||||
const [session, setSession] = useState<Me | null>(null);
|
||||
const [checked, setChecked] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
me()
|
||||
.then((r) => setUsername(r.username))
|
||||
.catch(() => setUsername(null))
|
||||
.then(setSession)
|
||||
.catch(() => setSession(null))
|
||||
.finally(() => setChecked(true));
|
||||
}, []);
|
||||
|
||||
if (!checked) return null;
|
||||
|
||||
if (!username) {
|
||||
return <Login onLoggedIn={() => me().then((r) => setUsername(r.username))} />;
|
||||
if (!session) {
|
||||
return <Login onLoggedIn={() => me().then(setSession)} />;
|
||||
}
|
||||
|
||||
return <Dashboard username={username} onLoggedOut={() => setUsername(null)} />;
|
||||
return <Dashboard session={session} onLoggedOut={() => setSession(null)} />;
|
||||
}
|
||||
|
||||
+6
-1
@@ -45,7 +45,12 @@ export function logout(): Promise<{ ok: true }> {
|
||||
return request("/api/auth/logout", { method: "POST" });
|
||||
}
|
||||
|
||||
export function me(): Promise<{ username: string }> {
|
||||
export interface Me {
|
||||
username: string;
|
||||
authMethod: "local" | "oidc";
|
||||
}
|
||||
|
||||
export function me(): Promise<Me> {
|
||||
return request("/api/auth/me");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { getHosts, getDevices, logout, type HostSummary, type Device } from "../api";
|
||||
import { getHosts, getDevices, logout, type HostSummary, type Device, type Me } from "../api";
|
||||
import { HostCard } from "../components/HostCard";
|
||||
import { DeviceTable } from "../components/DeviceTable";
|
||||
|
||||
const POLL_MS = 15000;
|
||||
|
||||
export function Dashboard({ username, onLoggedOut }: { username: string; onLoggedOut: () => void }) {
|
||||
export function Dashboard({ session, onLoggedOut }: { session: Me; onLoggedOut: () => void }) {
|
||||
const [hosts, setHosts] = useState<HostSummary[]>([]);
|
||||
const [devices, setDevices] = useState<Device[]>([]);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -41,9 +41,16 @@ export function Dashboard({ username, onLoggedOut }: { username: string; onLogge
|
||||
<header className="dashboard-header">
|
||||
<h1>Homelab Monitor</h1>
|
||||
<div>
|
||||
<span className="username">{username}</span>
|
||||
<span className="username">{session.username}</span>
|
||||
<button
|
||||
onClick={async () => {
|
||||
if (session.authMethod === "oidc") {
|
||||
// Full-page navigation, not a fetch -- Authentik needs a real
|
||||
// browser request to clear its own session cookie before
|
||||
// redirecting back here. See docs/oidc-setup.md.
|
||||
window.location.href = "/api/auth/oidc/logout";
|
||||
return;
|
||||
}
|
||||
await logout();
|
||||
onLoggedOut();
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user