Show the account controls the deployment actually has

The sidebar decided which auth mode was live from enterpriseAuthBase,
so any deployment with VITE_ENTERPRISE_AUTH_BASE_URL set rendered the
enterprise block -- and compose sets it unconditionally, so the tenant
picker can exist. On a single-tenant stack with local login on, that
meant the local block could never render: no username, no role, no
Change password, no Log out, and in their place a "Sign in" link
pointing at enterprise-auth's OIDC route, which is disabled unless
OIDC_ISSUER_URL is configured. A dead link where the account controls
should be.

The build-time flag was never the right thing to ask. api registers
/auth/* only when LOCAL_AUTH_ENABLED is set and ENTERPRISE_AUTH_URL is
not, so the frontend cannot know the mode from its own build args --
the two can disagree, and here they did. getLocalSession already
distinguishes 'disabled' (a 404 from /auth/session) from null (a 401,
logged out); the sidebar collapsed both to null and threw the answer
away. It now keeps that distinction and branches on it, so the mode
comes from what the server actually serves.

Logged out under local auth, the sidebar previously rendered no auth
block at all -- no way back to the login page from the nav. It now
offers Sign in, pointing at /login.

Neither block renders until the probe lands, so nothing flashes the
wrong mode on load.

Signed-off-by: John Coffey <[email protected]>
This commit is contained in:
2026-09-04 17:42:26 -07:00
parent 5374c1946a
commit dd5d5a77c3
+36 -14
View File
@@ -42,9 +42,27 @@
}); });
let localSession: LocalSession | null = $state(null); let localSession: LocalSession | null = $state(null);
// Whether the server actually serves local auth, which is not the
// same question as whether this bundle was built with it enabled.
// api registers /auth/* only when LOCAL_AUTH_ENABLED is set AND
// ENTERPRISE_AUTH_URL is not (see cmd/api/main.go's authorizer
// switch), so getLocalSession's 'disabled' -- a 404 from
// /auth/session -- is the only trustworthy signal of which mode is
// live. Deciding from enterpriseAuthBase alone got this wrong:
// compose sets VITE_ENTERPRISE_AUTH_BASE_URL unconditionally so the
// tenant picker can exist, so that check was true even on a
// single-tenant deployment whose actual authenticator was local
// login, and the local block below could never render.
//
// null means "not yet known" -- neither block renders until the
// probe lands, rather than flashing the wrong one.
let localAuthAvailable: boolean | null = $state(localAuthEnabled ? null : false);
$effect(() => { $effect(() => {
if (!localAuthEnabled) return; if (!localAuthEnabled) return;
getLocalSession().then((s) => (localSession = s === 'disabled' ? null : s)); getLocalSession().then((s) => {
localAuthAvailable = s !== 'disabled';
localSession = s === 'disabled' ? null : s;
});
}); });
// The Users nav item only ever makes sense for local-auth mode's // The Users nav item only ever makes sense for local-auth mode's
@@ -90,7 +108,23 @@
<button type="button" class="close-mobile" onclick={onCloseMobile} aria-label="Close menu"></button> <button type="button" class="close-mobile" onclick={onCloseMobile} aria-label="Close menu"></button>
</div> </div>
{#if enterpriseAuthBase} {#if localAuthAvailable}
<div class="tenant">
{#if localSession}
<div class="tenant-pill">
<span class="dot" aria-hidden="true"></span>
<span class="tenant-name">{localSession.username}</span>
<span class="role">{localSession.role}</span>
</div>
<a class="switch" href="/account">Change password</a>
<button type="button" class="switch logout-btn" onclick={handleLogout} disabled={loggingOut}>
{loggingOut ? 'Signing out…' : 'Log out'}
</button>
{:else}
<a class="switch signin" href="/login">Sign in</a>
{/if}
</div>
{:else if localAuthAvailable === false && enterpriseAuthBase}
<div class="tenant"> <div class="tenant">
{#if session} {#if session}
<div class="tenant-pill"> <div class="tenant-pill">
@@ -103,18 +137,6 @@
<a class="switch signin" href="{enterpriseAuthBase}/auth/oidc/login">Sign in</a> <a class="switch signin" href="{enterpriseAuthBase}/auth/oidc/login">Sign in</a>
{/if} {/if}
</div> </div>
{:else if localAuthEnabled && localSession}
<div class="tenant">
<div class="tenant-pill">
<span class="dot" aria-hidden="true"></span>
<span class="tenant-name">{localSession.username}</span>
<span class="role">{localSession.role}</span>
</div>
<a class="switch" href="/account">Change password</a>
<button type="button" class="switch logout-btn" onclick={handleLogout} disabled={loggingOut}>
{loggingOut ? 'Signing out…' : 'Log out'}
</button>
</div>
{/if} {/if}
<nav aria-label="Main"> <nav aria-label="Main">