Skip to content

[Stage 2 / P0] UX: first-run token modal + drop ?token= on first access #25

Description

@modacker

[Stage 2 / P0] UX: first-run token modal + drop ?token= on first access

Author: @modacker
Source review: docs/REVIEW-sihankor-baselines-2026-08-28.md
Part 4 Tier 1 items #1 + #2.
Related PR: modacker/MiniMax-Code-Plugins#23
(round 7 already shipped the closeApiKeyModal / openApiKeyModal
pattern that this issue will reuse for the onboarding modal).

Why

server.js:55–66 prints the first-run token to stdout in a 14-line
ASCII box:

══════════════════════════════════════
  mcode-webui auth token
  ...
  Save this token — it is shown ONCE.
  ...
══════════════════════════════════════

This token can leak via:

  • Shell history (terminal scrollback)
  • Docker log (docker logs <container>)
  • systemd journal
  • Screen share (Zoom, Meet, Discord, etc.)

SECURITY-NOTES.md:18–20 already acknowledges that ?token=
leaks via browser history, referer header, and shoulder-surf. The
two problems are linked: once the user has the token, they should
not be sending it in URLs.

What

1. First-run token modal (replaces stdout dump)

Frontend SPA detects first-run via ?onboarding=1 query or
tokenAcknowledged: false from /api/settings. Show a centered
modal that:

  • Displays the token in a copy-to-clipboard box
  • Displays the LAN URL (http://<lan-ip>:8080/)
  • Requires the user to click "I have saved this token" before
    it can close
  • On click: POSTs acknowledgement to /api/settings to set
    tokenAcknowledged: true, then drops the ?onboarding=1 query

Server-side: remove the stdout ASCII box; replace with
console.log("token persisted to <path>").

2. ?token= drop on first validated access

First request with ?token=: server validates, sets an
Authorization: Bearer-equivalent state (or httpOnly cookie), then
302-redirects to the same path without the query string. Subsequent
requests use the Authorization header.

Onboarding modal explains why the header is better.

Acceptance criteria

  • First start with empty settings.json: server prints a
    one-liner "token persisted to /Users/.../settings.json", no
    ASCII box
  • Browser opens http://127.0.0.1:8080/?onboarding=1 (or auto-
    redirected from any other first-load path) → centered modal
    with copy-to-clipboard token + LAN URL + "I have saved this
    token" button
  • Modal cannot close without the button click; the button POSTs
    tokenAcknowledged: true then redirects to clean URL
  • After acknowledgment, getSettingsSnapshot() no longer
    returns currentToken (current behavior)
  • Browser opening http://<host>/?token=<valid> is 302-redirected
    to http://<host>/ (query string stripped)
  • Subsequent requests use the Authorization header (not the
    query string); existing localStorage webui_token behavior
    preserved
  • npm test passes (target 460/0/2)
  • SiHankor Baseline 2 ("信息洪流") improves — first-run
    operator attention is now on a single on-screen action
    ("save the token") rather than scanning terminal scrollback

Out of scope (covered in other issues)

  • Anomaly channel + bell icon — see Stage 1 issue
  • Slash command autocomplete (governance commands marked ⚠️) —
    see Stage 2 follow-up
  • Multi-tier tokens (READ_TOKEN / WRITE_TOKEN) — see Tier 3 in
    the review doc

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