Skip to content

Remove the http://localhost:9926 redirectUri fallback — silent loopback default turns missing config into an authorization-code interception hazard #208

Description

@heskew

Problem

src/lib/config.ts:177:

const baseRedirectUri = expandedOptions.redirectUri || pluginDefaults.redirectUri || 'http://localhost:9926/oauth';

A server-side authorization plugin silently falls back to a plain-HTTP loopback redirect base when redirectUri isn't configured. Observed live on a Fabric-hosted deployment: the GitHub IdP hop was constructed as redirect_uri=http://localhost:9926/oauth/github/callback, so every connector authentication dead-ended at GitHub's "redirect_uri is not associated with this application" interstitial.

Why it's a security issue, not just a config footgun

GitHub happens to fail safe with a warning page. An IdP with a looser redirect policy (several treat loopback redirects permissively for native-app flows) would deliver the authorization code to whatever is listening on the end user's own localhost:9926. A silent default converts a missing config value into a code-interception hazard instead of a loud startup failure.

Fix

  1. Remove the localhost fallback entirely: no redirectUri and no derivable public base → fail closed at config load with an error naming the missing key.
  2. When mcp.issuer is configured, derive provider callbacks as issuer + '/oauth/<provider>/callback' — this matches the callback shape the enable tooling already instructs operators to register, and it keeps the value env-driven. (Consumer-side note: the obvious consumer fix redirectUri: ${PUBLIC_URL}/oauth is defeated by Harper's whole-token-only env interpolation — mcp.resource: ${FLAIR_MCP_ISSUER}/mcp never interpolates (whole-token-only env expansion) — every claude.ai connect fails invalid_target tpsdev-ai/flair#1180 — which is exactly why the derivation belongs plugin-side.)
  3. If a literal loopback base is ever legitimate (local dev), make it opt-in and log it loudly at startup.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions