@page "/admin/api-keys" @using ZB.MOM.WW.ScadaBridge.Security @using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Security @attribute [Authorize(Policy = AuthorizationPolicies.RequireAdmin)] @inject IInboundApiKeyAdmin ApiKeyAdmin @inject NavigationManager NavigationManager @inject IDialogService Dialog

API Key Management

@if (_loading) { } else if (_errorMessage != null) {
@_errorMessage
} else {
@if (_keys.Count == 0) {

No API keys configured.

} else if (!FilteredKeys.Any()) {

No API keys match the filter.

} else { @foreach (var key in FilteredKeys) { }
Key ID Name Methods Actions
@TruncateKeyId(key.KeyId) @key.Name @if (!key.Enabled) { Disabled } @key.Methods.Count
} }
@code { // Inbound-API key re-arch (C3): this page reads keys from the IInboundApiKeyAdmin seam // (string KeyId, method-scopes) rather than the SQL Server ApiKey entity. The seam has no // retrievable hash, so the old masked Key-Hash column is gone; KeyId identifies each row. private List _keys = new(); private bool _loading = true; private string? _errorMessage; private string _search = string.Empty; private ToastNotification _toast = default!; private IEnumerable FilteredKeys => string.IsNullOrWhiteSpace(_search) ? _keys : _keys.Where(k => k.Name?.Contains(_search, StringComparison.OrdinalIgnoreCase) ?? false); protected override async Task OnInitializedAsync() { await LoadDataAsync(); } private async Task LoadDataAsync() { _loading = true; _errorMessage = null; try { _keys = (await ApiKeyAdmin.ListAsync()).ToList(); } catch (Exception ex) { _errorMessage = $"Failed to load API keys: {ex.Message}"; } _loading = false; } // Show a short, recognizable prefix of the opaque KeyId rather than the full 32-char value. private static string TruncateKeyId(string keyId) { if (string.IsNullOrEmpty(keyId)) return keyId; return keyId.Length <= 12 ? keyId : keyId[..12] + "…"; } private async Task ToggleKey(InboundApiKeyInfo key) { try { var newEnabled = !key.Enabled; // The seam persists; there is no separate SaveChangesAsync. await ApiKeyAdmin.SetEnabledAsync(key.KeyId, newEnabled); _toast.ShowSuccess($"API key '{key.Name}' {(newEnabled ? "enabled" : "disabled")}."); await LoadDataAsync(); } catch (Exception ex) { _toast.ShowError($"Toggle failed: {ex.Message}"); } } private async Task DeleteKey(InboundApiKeyInfo key) { var confirmed = await Dialog.ConfirmAsync( "Delete API Key", $"Delete API key '{key.Name}'? This cannot be undone.", danger: true); if (!confirmed) return; try { await ApiKeyAdmin.DeleteAsync(key.KeyId); _toast.ShowSuccess($"API key '{key.Name}' deleted."); await LoadDataAsync(); } catch (Exception ex) { _toast.ShowError($"Delete failed: {ex.Message}"); } } }