/** The fixed machine contract shared by the Authentik catalog and auth diagnostics. */ export type AuthDiagnosticCode = | "auth_ready" | "auth_config_incomplete" | "auth_config_invalid" | "auth_session_store_invalid" | "local_user_registry_invalid" | "local_admin_missing" | "oidc_secret_missing" | "oidc_discovery_unreachable" | "oidc_issuer_mismatch" | "oidc_jwks_unreachable" | "oidc_group_catalog_unreachable" | "oidc_group_catalog_unauthorized" | "oidc_mapped_group_missing" | "oidc_mapped_group_ambiguous" | "oidc_groups_claim_invalid" | "oidc_device_flow_unavailable"; export interface AuthDiagnostic { level: "error" | "info"; code: AuthDiagnosticCode; message: string; field?: string; } export interface AuthDiagnostics { ready: boolean; mode: "local" | "oidc" | "upstream" | "none" | "mock"; checks: readonly AuthDiagnostic[]; } const diagnosticCodes = new Set([ "auth_ready", "auth_config_incomplete", "auth_config_invalid", "auth_session_store_invalid", "local_user_registry_invalid", "local_admin_missing", "oidc_secret_missing", "oidc_discovery_unreachable", "oidc_issuer_mismatch", "oidc_jwks_unreachable", "oidc_group_catalog_unreachable", "oidc_group_catalog_unauthorized", "oidc_mapped_group_missing", "oidc_mapped_group_ambiguous", "oidc_groups_claim_invalid", "oidc_device_flow_unavailable", ]); const diagnosticModes = new Set(["local", "oidc", "upstream", "none", "mock"]); const fieldCodes = new Set(["oidc_mapped_group_missing", "oidc_mapped_group_ambiguous"]); function exactObject(value: unknown, keys: readonly string[]): Record | undefined { if (!value || typeof value !== "object" || Array.isArray(value)) return undefined; const source = value as Record; const actual = Object.keys(source); return actual.length === keys.length && actual.every((key) => keys.includes(key)) ? source : undefined; } function safeText(value: unknown): value is string { return typeof value === "string" && value.length > 0 && value.length <= 512 && value.trim() === value && !/\p{Cc}/u.test(value); } /** Strict decoder for the machine contract shared with tht and the frontend. */ export function decodeAuthDiagnostics(value: unknown): AuthDiagnostics | undefined { const source = exactObject(value, ["ready", "mode", "checks"]); if (!source || typeof source.ready !== "boolean" || typeof source.mode !== "string" || !diagnosticModes.has(source.mode as AuthDiagnostics["mode"]) || !Array.isArray(source.checks) || source.checks.length === 0 || source.checks.length > 129) return undefined; const seen = new Set(); const checks: AuthDiagnostic[] = []; for (const value of source.checks) { const raw = value && typeof value === "object" && !Array.isArray(value) ? value as Record : undefined; const check = raw && exactObject(raw, raw.field === undefined ? ["level", "code", "message"] : ["level", "code", "message", "field"]); if (!check || (check.level !== "error" && check.level !== "info") || typeof check.code !== "string" || !diagnosticCodes.has(check.code as AuthDiagnosticCode) || !safeText(check.message) || (check.field !== undefined && !safeText(check.field))) return undefined; const code = check.code as AuthDiagnosticCode; if (check.field !== undefined && !fieldCodes.has(code)) return undefined; const key = `${code}\u0000${check.field ?? ""}`; if (seen.has(key)) return undefined; seen.add(key); checks.push({ level: check.level, code, message: check.message, ...(check.field === undefined ? {} : { field: check.field }), }); } if (source.ready) { if (checks.length !== 1 || checks[0].level !== "info" || checks[0].code !== "auth_ready" || checks[0].field !== undefined) return undefined; } else if (!checks.some(({ level }) => level === "error") || checks.some(({ code }) => code === "auth_ready")) return undefined; return { ready: source.ready, mode: source.mode as AuthDiagnostics["mode"], checks }; } /** A provider-specific proof that only the configured authorization groups exist. */ export interface GroupCatalog { verifyConfiguredGroups(names: readonly string[], signal: AbortSignal): Promise; }