Skip to content

me: token sign-in — /me works without an OIDC provider - #14

Merged
selic merged 2 commits into
mainfrom
feat/me-token-signin
Jul 25, 2026
Merged

me: token sign-in — /me works without an OIDC provider#14
selic merged 2 commits into
mainfrom
feat/me-token-signin

Conversation

@selic

@selic selic commented Jul 25, 2026

Copy link
Copy Markdown
Member

Summary

/me ("My MCP Access") previously dead-ended in Cannot GET /auth/login on deployments with static tokens only. The /api/me/* backend was already identity-agnostic — static-token principals get working prefs, personal credentials and per-user upstream sessions — the OIDC coupling lived entirely in the browser layer. This PR gives me.html the same sign-in panel admin.html already has, so /me works everywhere.

  • me.html: sign-in panel with "Sign in with Microsoft" (shown only when interactive login is configured) + bearer-token paste as break-glass (sessionStorage, distinct key from the admin page). The token's label is the identity the page keys prefs/credentials by. Sign-out and 401 handling degrade cleanly without the login routes; 403 (signed in, no role) is deliberately NOT treated as sign-out — bouncing it to the IdP would loop.
  • app.ts: /health gains a login capability flag; GET / redirects to /me on token-only deploys too. With login configured the UX is unchanged: session-less HTML GETs of / and /me still silently redirect to /auth/login; ?signin=token bypasses the gate for when the IdP is down.
  • me-api.ts: GET /api/me/access emits connect: null unless the one-click Connect flow is actually mounted (login + userConnect + secret store) — no more dead Connect buttons.
  • config.ts ⚠️ BREAKING: duplicate labels across MCP_TOKENS_* are now a ConfigError. Labels key /me prefs, personal credentials and per-user upstream links; a shared label silently shared that state across tokens (even across roles).
  • Docs: deploy-coolify.md troubleshooting row rewritten, README + CLAUDE.md updated.

Includes the Coolify deployment guide commit (a409677) this builds on.

Test plan

  • npm test — 211 passed (9 new: label collisions, /health.login, gate regression + ?signin=token bypass on a login-configured app, connect-metadata gating both ways)
  • npm run build clean
  • Manual (token-only dev server): //me; panel shows no Microsoft button; valid token signs in (bob · viewer); invalid token shows inline error; reload auto-signs-in from sessionStorage; sign-out returns to the panel without touching /auth/logout errors

🤖 Generated with Claude Code

selic and others added 2 commits July 25, 2026 08:46
The existing guides all assume docker compose on a host you control, where
volumes outlive containers. On a PaaS the container is recreated on every
deploy, and the image's `VOLUME /data` then resolves to an anonymous volume
that goes away with it — so each deploy silently starts from an empty
database and every upstream, role and grant is lost. Hit in production; the
failure looks like "the admin UI didn't save my settings".

Adds docs/deploy-coolify.md covering what lives on /data, the build settings
(the Dockerfile is under docker/, not the repo root), why the mount must be a
named volume rather than a host bind mount (the container runs as uid 1000,
and a named volume inherits node:node from the image while a host directory
arrives root-owned), deploying from the Coolify API, and a redeploy that
proves persistence. Ends with a troubleshooting table of the failures we
actually hit, including `Cannot GET /auth/login` on /me with static-token
auth, a literal `bao:…` reaching an upstream, doubled `Bearer`, and the
namespace charset rule.

README gets a "Hosting on a container PaaS" subsection — hosting is an axis
orthogonal to the three auth/secret scenarios, so it sits beside the table
rather than in it. .gitignore now excludes *.local.md for stand-specific
runbooks that must not be published.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The /api/me backend was already identity-agnostic: static-token
principals get working prefs, personal credentials and per-user
upstream sessions (proven by personal-sessions.test.ts). Only the
browser layer demanded the cookie flow. me.html now renders the same
sign-in panel as admin.html: "Sign in with Microsoft" when interactive
login is configured (surfaced via a new `login` flag on /health) plus
bearer-token paste as break-glass; the token's label is the identity.

With login configured nothing changes: session-less HTML GETs of /
and /me still silently redirect to /auth/login and signed-in users
land straight on the page. /me?signin=token bypasses the gate for
when the IdP is unavailable. Token-only deployments get / -> /me and
the token-only panel. /api/me/access now emits connect: null unless
the one-click Connect flow is actually mounted, so the UI never
renders dead Connect buttons.

BREAKING: duplicate labels across MCP_TOKENS_* are now a ConfigError.
Labels key /me prefs, personal credentials and per-user upstream
links — a shared label silently shared that state across tokens.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@selic
selic merged commit 6aff858 into main Jul 25, 2026
1 check passed
@selic
selic deleted the feat/me-token-signin branch July 25, 2026 06:29
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.

1 participant