Add Authelia as centralized authentication and OIDC provider

Authelia runs as a managed native service on Wild Central, providing
two integration patterns for network services:

- Forward-auth via HAProxy for apps without native SSO (Lua auth-request
  script intercepts requests, redirects unauthenticated users to login portal)
- OIDC provider for apps with native support (Gitea, Grafana, etc.)

Backend: new internal/authelia/ package with service manager, config
generation, file-based user management (argon2id), and OIDC client
management. API endpoints for status, config, users CRUD, and OIDC
clients CRUD.

HAProxy: config generator extended with lua-load, auth-request
directives, and Authelia backend. Auth directives scoped to session
cookie domain — only subdomains of the auth portal's parent are
eligible for forward-auth.

Frontend: Authentication page with enable/disable, user management,
OIDC client management (add/edit/delete), and protected domains
toggles. Advanced subsystem page for raw config view. Dashboard
service card and sidebar entries.
This commit is contained in:
2026-07-12 11:47:37 +00:00
parent 24bb976652
commit d796a79f79
27 changed files with 3097 additions and 11 deletions

View File

@@ -0,0 +1,90 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { autheliaApi } from '../services/api/authelia';
import type { CreateUserRequest, UpdateUserRequest, CreateOIDCClientRequest, UpdateOIDCClientRequest } from '../services/api/authelia';
export function useAuthelia() {
const queryClient = useQueryClient();
const statusQuery = useQuery({
queryKey: ['authelia', 'status'],
queryFn: () => autheliaApi.getStatus(),
staleTime: 10000,
});
const usersQuery = useQuery({
queryKey: ['authelia', 'users'],
queryFn: () => autheliaApi.listUsers(),
enabled: !!statusQuery.data?.enabled,
});
const oidcClientsQuery = useQuery({
queryKey: ['authelia', 'oidc', 'clients'],
queryFn: () => autheliaApi.listOIDCClients(),
enabled: !!statusQuery.data?.active,
});
const invalidateAll = () => {
queryClient.invalidateQueries({ queryKey: ['authelia'] });
queryClient.invalidateQueries({ queryKey: ['central', 'status'] });
};
const updateConfigMutation = useMutation({
mutationFn: (data: { enabled?: boolean; domain?: string; defaultPolicy?: string }) =>
autheliaApi.updateConfig(data),
onSuccess: invalidateAll,
});
const restartMutation = useMutation({
mutationFn: () => autheliaApi.restart(),
onSuccess: invalidateAll,
});
const createUserMutation = useMutation({
mutationFn: (req: CreateUserRequest) => autheliaApi.createUser(req),
onSuccess: invalidateAll,
});
const updateUserMutation = useMutation({
mutationFn: ({ username, ...req }: UpdateUserRequest & { username: string }) =>
autheliaApi.updateUser(username, req),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['authelia', 'users'] }),
});
const deleteUserMutation = useMutation({
mutationFn: (username: string) => autheliaApi.deleteUser(username),
onSuccess: invalidateAll,
});
const createOIDCClientMutation = useMutation({
mutationFn: (req: CreateOIDCClientRequest) => autheliaApi.createOIDCClient(req),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['authelia', 'oidc', 'clients'] }),
});
const updateOIDCClientMutation = useMutation({
mutationFn: ({ clientId, ...req }: UpdateOIDCClientRequest & { clientId: string }) =>
autheliaApi.updateOIDCClient(clientId, req),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['authelia', 'oidc', 'clients'] }),
});
const deleteOIDCClientMutation = useMutation({
mutationFn: (clientId: string) => autheliaApi.deleteOIDCClient(clientId),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['authelia', 'oidc', 'clients'] }),
});
return {
status: statusQuery.data,
isLoadingStatus: statusQuery.isLoading,
users: usersQuery.data?.users ?? [],
isLoadingUsers: usersQuery.isLoading,
oidcClients: oidcClientsQuery.data?.clients ?? [],
isLoadingClients: oidcClientsQuery.isLoading,
updateConfig: updateConfigMutation,
restart: restartMutation,
createUser: createUserMutation,
updateUser: updateUserMutation,
deleteUser: deleteUserMutation,
createOIDCClient: createOIDCClientMutation,
updateOIDCClient: updateOIDCClientMutation,
deleteOIDCClient: deleteOIDCClientMutation,
};
}