Add OIDC admin config page with auto-signup toggle
Some checks failed
CI / build (push) Successful in 1m12s
CI / docker (push) Successful in 50s
CI / deploy (push) Failing after 2m10s

Backend: add autoSignup field to OidcConfig, ClickHouse schema, repository,
and admin controller. Gate OIDC login when auto-signup is disabled and user
is not pre-created (returns 403).

Frontend: add OIDC admin page with full CRUD (save/test/delete), role-gated
Admin nav link parsed from JWT, and matching design system styles.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-14 13:56:02 +01:00
parent 377908cc61
commit 0c47ac9b1a
12 changed files with 802 additions and 14 deletions

View File

@@ -5,6 +5,7 @@ interface AuthState {
accessToken: string | null;
refreshToken: string | null;
username: string | null;
roles: string[];
isAuthenticated: boolean;
error: string | null;
loading: boolean;
@@ -13,6 +14,15 @@ interface AuthState {
logout: () => void;
}
function parseRolesFromJwt(token: string): string[] {
try {
const payload = JSON.parse(atob(token.split('.')[1]));
return Array.isArray(payload.roles) ? payload.roles : [];
} catch {
return [];
}
}
function loadTokens() {
return {
accessToken: localStorage.getItem('cameleer-access-token'),
@@ -39,6 +49,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
accessToken: initial.accessToken,
refreshToken: initial.refreshToken,
username: initial.username,
roles: initial.accessToken ? parseRolesFromJwt(initial.accessToken) : [],
isAuthenticated: !!initial.accessToken,
error: null,
loading: false,
@@ -61,6 +72,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
accessToken,
refreshToken,
username,
roles: parseRolesFromJwt(accessToken),
isAuthenticated: true,
loading: false,
});
@@ -88,6 +100,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
set({
accessToken: data.accessToken,
refreshToken: data.refreshToken,
roles: parseRolesFromJwt(data.accessToken),
isAuthenticated: true,
});
return true;
@@ -102,6 +115,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
accessToken: null,
refreshToken: null,
username: null,
roles: [],
isAuthenticated: false,
error: null,
});