Skip to content

WebUI: API keys generated from another origin appear as available slots instead of showing a warning #174

@dorukardahan

Description

@dorukardahan

Summary

API keys are stored in two layers: on-chain (smart contract token slots 0-254) and browser localStorage (key strings, labels, expiry). localStorage is origin-scoped, so keys generated from one origin (e.g., localhost:3090) are invisible from another origin (e.g., hosted deployment). The WebUI does not warn users about this, leading to potential silent key invalidation.

Actual behavior

When a user generates an API key on Origin A, then accesses the WebUI from Origin B:

  1. SlotManager shows the occupied slot as "available" (white circle) — useSlotStatus.ts:138-147 treats no-localData + not-revoked as available
  2. SlotStatusCompact shows "0 active, 255 available" — active only counts slots with localData
  3. ProviderApiKeyManager shows "0 existing keys" — reads from localStorage only
  4. Key generation can silently overwrite the Origin A key — findNextAvailableTokenIdFromData (useSlotStatus.ts:209-213) only checks localStorage for slot occupancy, not on-chain state
  5. BuildDrawer Step 3 shows "incomplete" even though on-chain slot is occupied

The only component that correctly identifies the gap is OnChainTokensView (OnChainTokensView.tsx:69-71), which shows "Unknown" tokens with an amber badge — but this view is buried in the wallet page, not shown during key generation.

Expected behavior

  • Slots with on-chain activity but no localStorage data should show as "unknown" (not "available")
  • A warning banner should appear when the system detects potential external keys (generation counter > 0 but no local keys)
  • Key generation should warn before potentially overwriting a slot that may have an active key from another origin
  • Slot grid should visually distinguish "unknown" slots from truly "available" ones

Root cause

useSlotStatus.ts:138-147 explicitly documents the ambiguity in a comment but defaults to treating unknown slots as available:

// Not revoked but no local data - could be:
// 1. Never used (available)
// 2. Used but localStorage lost (unknown)
// For slot visualization, we treat it as available unless we know it's occupied

The on-chain contract only tracks revokedBitmap (revoked/not-revoked), not whether a slot was ever used. Without a separate "used bitmap" or off-chain sync, the UI cannot definitively distinguish "never used" from "used elsewhere." However, the generation counter and local key count provide a reliable heuristic.

Proposed fix

A UX-only fix (no contract changes) in 3 phases:

Phase 1 — Detection layer:

  • Add externalSlotCount to useOnChainTokens.ts return value (heuristic: non-revoked, no localData, AND generation > 0 or has some local keys)
  • Add unknown count to SlotStats in useSlotStatus.ts

Phase 2 — Warning UI:

  • Add amber warning banner to ProviderApiKeyManager.tsx when external keys are detected
  • Add confirm dialog before key generation when generation > 0 and no local keys exist
  • Add "may have external keys" indicator to SlotStatusCompact.tsx

Phase 3 — Slot grid visualization:

  • Add unknown slot status type to useSlotStatus.ts
  • Render unknown slots with distinct color (amber) in SlotManager.tsx
  • Update legend to include "Unknown (possible external key)"

Will submit a PR with the implementation.

Repro notes

  1. Run WebUI on localhost:3090, connect wallet, generate an API key
  2. Note which slot was assigned (e.g., slot 0)
  3. Open WebUI on a different origin (or clear localStorage)
  4. Connect same wallet — slot 0 shows as "available" instead of warning
  5. Generate a new key — it may reuse slot 0, silently invalidating the first key

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions