Skip to content

feat(web-ui): detect and warn about API keys from other origins#175

Open
dorukardahan wants to merge 1 commit into0gfoundation:mainfrom
dorukardahan:fix/webui-external-key-detection
Open

feat(web-ui): detect and warn about API keys from other origins#175
dorukardahan wants to merge 1 commit into0gfoundation:mainfrom
dorukardahan:fix/webui-external-key-detection

Conversation

@dorukardahan
Copy link
Contributor

Summary

  • Added detection heuristic for API keys that may exist from another browser origin/device
  • Added "unknown" slot status type for ambiguous slots (not revoked, no localStorage data, but user has previous activity)
  • Added amber warning banner when external keys are detected
  • Added confirm dialog before key generation when slot collision is possible
  • Added unknown slot visualization (yellow circle) in slot grid

Why

API key strings are stored in origin-scoped localStorage, while token slots are tracked on-chain. When a user generates keys from one origin (e.g., localhost:3090) and later accesses the WebUI from a different origin, those slots appear as "available" instead of showing a warning. This can lead to silent key invalidation when the user generates a new key that reuses an occupied slot.

Files changed

File Change
useOnChainTokens.ts Added externalSlotCount return value using generation counter heuristic
useSlotStatus.ts Added 'unknown' slot status type and unknown count to SlotStats
ProviderApiKeyManager.tsx Added amber warning banner + confirm dialog before generation
SlotStatusCompact.tsx Added "unknown" count in compact header
SlotManager.tsx Added yellow circle icon, legend entry, and warning alert for unknown slots

How the heuristic works

A slot is marked "unknown" (instead of "available") when ALL of these are true:

  1. The slot is not revoked on-chain
  2. There is no localStorage data for this slot
  3. The user has interacted before (generation counter > 0 OR has at least one local key)

This prevents false positives for brand-new users (generation === 0, no keys) while catching the case where keys exist from another origin.

Edge cases handled

  • Brand-new user: No warning (generation === 0, no local keys → all slots truly available)
  • All slots from another origin: Warning banner + confirm dialog
  • Mixed slots: Unknown count shown alongside active count
  • Cleared localStorage: Same behavior as "another origin" — warning appears
  • Revoked slots: Handled correctly by on-chain bitmap, no change needed

Test plan

  • New user (no keys, generation=0): No warning, all slots available
  • Generate key on Origin A, view from Origin B: Warning banner visible, unknown slots in grid
  • Generate key with warning: Confirm dialog appears, can proceed or cancel
  • "Refresh All" clears warning (generation increments, bitmap resets)
  • Slot grid shows yellow circles for unknown slots with correct tooltip

Fixes #174

When a user generates API keys from one browser origin (e.g.,
localhost:3090), those key strings are stored in origin-scoped
localStorage. Accessing the WebUI from a different origin shows
these slots as "available" instead of warning the user.

Changes:
- Add externalSlotCount heuristic to useOnChainTokens (generation
  counter + local key count)
- Add 'unknown' slot status type to useSlotStatus for ambiguous slots
- Add amber warning banner to ProviderApiKeyManager when external
  keys are detected
- Add confirm dialog before key generation when slot collision is
  possible
- Add unknown slot indicator to SlotStatusCompact header
- Add yellow circle icon and legend entry for unknown slots in
  SlotManager grid

Fixes 0gfoundation#174
@vercel
Copy link

vercel bot commented Feb 23, 2026

@dorukardahan is attempting to deploy a commit to the 0g-Frontend Team on Vercel.

A member of the Team first needs to authorize it.

@dorukardahan
Copy link
Contributor Author

Self-review: improvements from a second pass

Design decision — heuristic vs definitive detection:
The externalSlotCount heuristic uses generation > 0 || localKeys.length > 0 to determine if a user has interacted before. This is conservative:

  • False negative: impossible (if generation > 0, user definitely interacted)
  • False positive: only if generation > 0 AND all non-revoked slots are truly unused (rare edge case after "Refresh All")

The false positive after "Refresh All" is acceptable because: generation increments, bitmap resets, but some slots may legitimately be empty. The warning is informational, not blocking.

Potential improvement for a follow-up PR:
The findNextAvailableTokenIdFromData function still treats unknown slots as available for allocation. A more defensive approach would skip unknown slots and only use truly available ones (status === 'available'). Left as-is to minimize behavioral changes in this PR — the confirm dialog provides sufficient protection.

No breaking changes:

  • SlotStatus type is extended (additive: 'unknown' added), not changed
  • SlotStats.unknown is a new field (additive), existing consumers won't break
  • All existing tests (if any) should pass since 'available' behavior is preserved for new users

@vercel
Copy link

vercel bot commented Mar 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
0g-serving-user-broker Ready Ready Preview, Comment Mar 6, 2026 11:10am

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant