Zum Hauptinhalt springen
Sachbearbeiter-Cockpit

Auth & Rechte

Die Anmeldung gehört zur Library und ist fest eingebaut — es gibt keinen Login-Slot. Du lieferst die OIDC-Settings, alles andere macht BaseCockpit: Redirect zu Keycloak, Token-Verwaltung, stille Erneuerung und das Anhängen des Tokens an jeden API-Aufruf.

Der Ablauf

authConfig.json laden (fetch, no-store)
│ fehlt / unvollständig → Fehlerbildschirm

AuthProvider (react-oidc-context)
│ nicht angemeldet → Login-Screen, leitet automatisch weiter

Keycloak: Authorization-Code-Flow mit PKCE
│ Callback: Tokens da, Auth-Parameter werden aus der URL geräumt

angemeldet → Rollen auswerten → App-Übersicht
↻ automaticSilentRenew hält die Session frisch

Der Login-Screen löst den Redirect selbst aus, sobald er erscheint. Er zeigt nur dann eine Schaltfläche zum erneuten Versuch, wenn die Anmeldung fehlgeschlagen ist. Die Einstellungen dazu stehen in der authConfig.json; automaticSilentRenew ist standardmäßig aktiv.

Abgemeldet wird über das Profil-Menü in der Kopfzeile — das löst einen OIDC-Signout-Redirect aus.

App-Rechte über Keycloak-Rollen

Sichtbarkeit von Apps steuert die Library über Realm-Rollen mit dem Präfix cockpit-:

Realm-Rolle "cockpit-akten" → App mit id "akten" ist sichtbar
Realm-Rolle "cockpit-anträge" → App mit id "anträge" ist sichtbar

Aktiv wird die Prüfung nur mit "checkPermission": true in der authConfig.json. Ohne das Feld (Default) sind alle konfigurierten Apps sichtbar.

Geprüft wird an zwei Stellen: beim Aufbau der Übersicht (nicht erlaubte Kacheln fehlen) und beim Auflösen der URL (/:appId per Deep-Link → fehlt die Rolle, geht es zurück auf die Übersicht).

Die erlaubten App-Ids kannst du auch selbst lesen:

import { useAllowedApps, APP_ROLE_PREFIX } from '@gentics/cockpit/core';

const allowed = useAllowedApps(); // z. B. ["akten", "anträge"]
APP_ROLE_PREFIX; // "cockpit-"

Wer ist angemeldet?

import { useUserInfo, useCurrentUser } from '@gentics/cockpit/core';

const { data: info } = useUserInfo(); // normalisiert: name, username, email, …
const { data: me } = useCurrentUser(); // rohe Antwort von /Me

useUserInfo() fragt zuerst das ActaNova-Backend (/Me) und nimmt daraus Vor-/Nachname (bzw. displayName) und E-Mail. Liefert der Aufruf nichts oder schlägt er fehl, fällt der Hook auf die Token-Claims zurück (name, preferred_username, email). Das Ergebnis ist pro User (sub) gecacht und gilt für die Sitzung als unveränderlich.

Kopfzeile und Profil-Menü

Das Standard-Profil-Menü (UserMenu) zeigt Initialen-Avatar, Name, E-Mail und „Abmelden"; sind in der /Me-Antwort role bzw. tenantName enthalten, erscheinen sie als Zusatzzeilen.

Du kannst es in einer eigenen Kopfzeile weiterverwenden:

import { UserMenu, type HeaderComponentProps } from '@gentics/cockpit/core';

function MeinHeader({ branding, inApp, onHome, onLogout }: HeaderComponentProps) {
return (
<header className="flex items-center gap-3 border-b px-6 py-3">
{inApp && <button onClick={onHome}>← Übersicht</button>}
{branding?.logo}
<span className="font-semibold">{branding?.name ?? 'Sachbearbeiter-Cockpit'}</span>
<UserMenu onLogout={onLogout} />
</header>
);
}

<BaseCockpit apps={apps} HeaderComponent={MeinHeader} />

UserMenu liest Auth-Zustand und User-Infos selbst und braucht keine Pflicht-Props; ohne onLogout nimmt es den OIDC-Signout-Redirect.

Weiter