Skip to content

feat(auth): pass through login_hint + prompt parameters to upstream IdPs #40

Description

@mitselek

Request

Allow callers of `GET /auth/` to pass `login_hint` and `prompt` query parameters through to the upstream OAuth flow (oauth.ee → Google / Apple / etc.).

Current behaviour

`routes/auth/[provider].get.js` constructs a fixed 5-parameter set for the redirect to `oauth.ee`: `client_id`, `redirect_uri`, `response_type`, `scope`, `state`. Caller-supplied query params on `/auth/?login_hint=...` are silently dropped — they don't make it into the `URLSearchParams` construction. The `state` JWT carries only `{ next: }`, with no channel for app-specific extras.

This means 3rd-party frontends cannot:

  • Prefill the account picker at the upstream IdP with `login_hint=user@example.com` (the user re-types or re-picks every session)
  • Trigger silent re-auth with `prompt=none` when a user's IP has shifted and the JWT has expired but their browser still has a valid IdP session

Both are standard OIDC parameters supported by every major IdP (Google, Apple, Microsoft, etc.).

Proposed change

Forward an allowlisted set of caller query params into the upstream URLSearchParams construction. Start with `login_hint` and `prompt` — the two with concrete demand. Other OIDC params can be added later if requested.

```js
// routes/auth/[provider].get.js (sketch)
const ALLOWED_PASSTHROUGH = ['login_hint', 'prompt'];
const params = new URLSearchParams({
client_id, redirect_uri, response_type, scope, state
});
for (const key of ALLOWED_PASSTHROUGH) {
const v = event.query[key];
if (v) params.set(key, String(v));
}
```

No `state` JWT changes needed; the params travel as plain OAuth params.

Forward-compat already shipped in mvox

The mvox web app (https://multivox.pages.dev) already includes `login_hint` in its OAuth init URL construction. It's silently dropped today; the day this lands, the feature lights up across mvox with zero client code change. Any other 3rd-party frontend can do the same defensively.

Why this matters for 3rd-party frontends

Entu's user-facing pattern is browser-direct + IP-bound JWT (per entu/webapp's reference implementation, also documented in Patterns/entu/3rd-party-frontend-browser-direct and the entu/research case study added in entu/research#50).

Because the JWT is IP-bound with no refresh flow, users re-authenticate every time their IP shifts (WiFi ↔ cellular, VPN rotation, travel). This is a documented, intentional security property. But because we cannot pass `login_hint` or `prompt=none`, every re-auth is a full provider-picker + IdP login round-trip — even for users who just refreshed two minutes ago on the same machine.

`login_hint` lets the frontend say "the user was `alice@example.com` last time, prefill that" — the IdP shows a one-click confirm instead of a full account picker.

`prompt=none` (used carefully, with graceful fallback) lets the frontend attempt silent re-auth — the IdP either issues a fresh assertion silently (user has a live session there) or returns an error, at which point the frontend bounces the user through the normal flow.

Neither weakens Entu's threat model. The IP-binding still holds. The user is still authenticated at the IdP. The frontend just stops asking them to re-type / re-confirm context the IdP already has.

Acceptance criteria

  • `GET /auth/?login_hint=` forwards `login_hint` to oauth.ee
  • `GET /auth/?prompt=none` forwards `prompt` to oauth.ee
  • Other caller query params remain silently dropped (no surprise passthrough; allowlist is explicit)
  • Unit test covering passthrough for both params

Related

  • mvox case study: entu/research#50 (Section E3 references this ask)
  • Brilliant KB pattern: `Patterns/entu/3rd-party-frontend-browser-direct` (canonical source for the case study)
  • mvox forward-compat: `mvox-dev/mvox_v4e_web@fc99291` includes `login_hint` in OAuth init URL construction

Origin

Filed by mvox-dev team-lead (Palestrina) per PO direction 2026-05-23, after the 4-hotfix CHORE-B production-test cycle made the re-auth UX cost visible.

(MVOX:Palestrina)

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