Skip to content

server: fail login fast when the configured issuer is not the proxy-advertised one - #314

Closed
qu0b wants to merge 1 commit into
masterfrom
qu0b/fix-login-issuer-scope-mismatch
Closed

server: fail login fast when the configured issuer is not the proxy-advertised one#314
qu0b wants to merge 1 commit into
masterfrom
qu0b/fix-login-issuer-scope-mismatch

Conversation

@qu0b

@qu0b qu0b commented Jul 20, 2026

Copy link
Copy Markdown
Member

Problem

panda auth login from a config that predates the Authentik switch dies in the browser with Dex's "Bad Request — request was missing parameters" page:

dex.../device/callback?error=invalid_scope&error_description=Unrecognized+scope(s)+["workflows"]

Root cause: /auth/metadata advertises a coherent login contract — issuer plus the scope set that issuer understands — but BeginLogin mixed halves of two contracts. It adopted the advertised scopes while keeping the configured issuer. Since the production proxy started advertising the workflows scope (wagie passthrough, Authentik-only — Authentik cross-grants the audience; Dex rejects unknown scopes outright), every client still configured for the legacy Dex issuer mints a device code that is guaranteed to fail after the user has already entered it in the browser.

There is no outcome where a Dex-configured client gets full functionality — Dex physically cannot mint the workflows audience — so degrading silently (dropping the scope) would just recreate the opaque-401 problem this discovery mechanism was built to prevent.

Fix

Treat issuer + scopes as one contract at login:

  • Issuers match (up to a trailing slash) → adopt advertised scopes, exactly as before.
  • Issuers differ → refuse before any device code is minted, with the migration path in the error:
the proxy advertises issuer https://authentik...panda-proxy/ but this server is configured for
https://dex...; re-run `panda init` to adopt the advertised issuer, restart panda-server, then retry login
  • Older proxy advertising no issuer → gate skipped, today's behavior.

The trailing-slash normalization matters: Authentik's issuer requires the slash while other layers may carry it trimmed — a naive comparison would have broken logins for every correctly configured client.

Refresh flows are untouched: Dex stays a trusted issuer for existing tokens; only interactive login becomes the migration point, which matches the platform's dual-issuer intent.

Testing

  • TestBeginLoginIssuerGate: mismatch refuses with actionable error and no client built; trailing-slash difference is not a mismatch; absent advertised issuer skips the gate.
  • TestBeginLoginScopeSelection / TestFetchProxyLoginAuth updated for the widened discovery contract (issuer + scopes).
  • go test -race ./pkg/server/, go vet, golangci-lint: clean.

…sed one

/auth/metadata advertises a coherent login contract: issuer plus the scope
set that issuer understands. BeginLogin mixed halves of two contracts by
applying the advertised scopes to whatever issuer the local config pinned.
A config from before the Authentik switch pointed at the legacy Dex issuer,
so login requested the Authentik-only "workflows" scope from Dex, which
rejects unknown scopes: the device flow died in the browser with
invalid_scope ("Bad Request - request was missing parameters") after the
user had already entered the code.

Refuse to start the device flow when the advertised issuer differs from the
configured one, and say how to migrate (re-run panda init, restart the
server). Issuer comparison ignores a trailing slash: Authentik's issuer
requires it while other layers may carry it trimmed. Older proxies that
advertise no issuer keep today's behavior.
@github-actions

Copy link
Copy Markdown
Contributor

🐼 Smoke eval — 1d61697: ✅ 8/8 pass

📊 Interactive report — tokens p50 18,041 · tokens/solve 19,968.

Reference points: master@2042fdc 100% · v0.38.6 96%.

question result tokens tools
forky_node_coverage 17,082 6
tracoor_node_coverage 19,000 9
mainnet_block_arrival_p50 16,816 9
list_datasources 13,009 2
block_count_24h 16,207 7
missed_slots_24h 21,225 15
chartkit_default_arrival_distribution 32,778 15
storage_upload_session_scoped 23,630 19
🔭 Langfuse traces (8 runs; ⚠️ = failed)

The report walks this branch's commits against the master baseline and the most recent release. A self-contained copy is in the run's eval-smoke-* artifact.

@qu0b qu0b closed this Jul 21, 2026
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